@rxdi/forms 0.7.230 → 0.7.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -327,17 +327,17 @@ function ErrorTemplate(input: AbstractInput) {
327
327
 
328
328
  ### 1. Grouping Multiple Inputs (Checkbox Groups)
329
329
 
330
- By default, inputs with the same `name` attribute are treated as a single value (last write wins). However, for checkboxes, you often want an array of values.
330
+ By default (`multi: false`), inputs with the same `name` attribute behave like radio buttons (single selection). To allow multiple selections (array of values), set `multi: true` in the form options.
331
331
 
332
332
  **Scenario:** A list of permissions where multiple can be selected.
333
333
 
334
334
  ```typescript
335
335
  @Form({
336
336
  name: 'permissions-form',
337
- multi: true // Enable multi-value binding for same-name inputs
337
+ multi: true // Enable multi-value binding for SAME-NAME inputs
338
338
  })
339
339
  form = new FormGroup({
340
- roles: [] // Will be an array of values
340
+ roles: [] // Will be an array of values ['admin', 'viewer']
341
341
  });
342
342
  ```
343
343
 
@@ -347,19 +347,17 @@ form = new FormGroup({
347
347
  <label> <input name="roles" type="checkbox" value="viewer" /> Viewer </label>
348
348
  ```
349
349
 
350
- If the user checks "Admin" and "Viewer", `form.value.roles` will be `['admin', 'viewer']`.
350
+ ### 2. Single Selection Checkbox (Default Behavior)
351
351
 
352
- ### 2. Single Selection Checkbox (Radio Behavior with Checkboxes)
353
-
354
- If you want multiple checkboxes to act like a radio button (only one valid at a time) but with uncheck capability:
352
+ If you want multiple checkboxes to act like a radio button (only one valid at a time) but with uncheck capability, simply use the default `multi: false`.
355
353
 
356
354
  ```typescript
357
355
  @Form({
358
356
  name: 'settings-form',
359
- multi: false // Default behavior
357
+ // multi: false // Default behavior
360
358
  })
361
359
  form = new FormGroup({
362
- mode: ''
360
+ mode: '' // Will be a single string 'dark' or 'light'
363
361
  });
364
362
  ```
365
363
 
@@ -368,9 +366,32 @@ form = new FormGroup({
368
366
  <label> <input name="mode" type="checkbox" value="light" /> Light </label>
369
367
  ```
370
368
 
371
- Checking "Dark" unchecks "Light" automatically.
369
+ ### 3. Per-Field Multi-Select Override
370
+
371
+ You can mix single-select and multi-select groups in the same form by keeping the global `multi: false` (default) and adding the `multiple` attribute to specific inputs.
372
+
373
+ ```typescript
374
+ @Form({
375
+ name: 'mixed-form',
376
+ multi: false // Default (Single Select)
377
+ })
378
+ form = new FormGroup({
379
+ mode: '', // Single value
380
+ tags: [] // Array of values
381
+ });
382
+ ```
383
+
384
+ ```html
385
+ <!-- Single Select (Radio behavior) -->
386
+ <input name="mode" type="checkbox" value="A" />
387
+ <input name="mode" type="checkbox" value="B" />
388
+
389
+ <!-- Multi Select (Array behavior) via 'multiple' attribute -->
390
+ <input name="tags" type="checkbox" value="news" multiple />
391
+ <input name="tags" type="checkbox" value="tech" multiple />
392
+ ```
372
393
 
373
- ### 3. Framework-Agnostic Usage (Vanilla JS)
394
+ ### 4. Framework-Agnostic Usage (Vanilla JS)
374
395
 
375
396
  You can use this library without Decorators or LitHtml, with any UI library or vanilla HTML.
376
397
 
@@ -18,7 +18,10 @@ function Form(options = {
18
18
  if (!(this[name] instanceof form_group_1.FormGroup)) {
19
19
  throw new Error('Value provided is not an instance of FormGroup!');
20
20
  }
21
- this[name].setParentElement(this).setOptions(options).prepareValues();
21
+ this[name]
22
+ .setParentElement(this)
23
+ .setOptions(options)
24
+ .prepareValues();
22
25
  if (options.model && this[options.model]) {
23
26
  this[name].patchValue(this[options.model]);
24
27
  }
@@ -1,5 +1,8 @@
1
1
  import { LitElement } from '@rxdi/lit-html';
2
2
  import { AbstractControl, AbstractInput, DeepPropType, ErrorObject, FormInputOptions, FormOptions, NestedKeyOf, UnwrapValue, ValidatorFn } from './form.tokens';
3
+ export interface AbstractInputWithBound extends AbstractInput {
4
+ _bound?: boolean;
5
+ }
3
6
  export declare class FormGroup<T = FormInputOptions, E = {
4
7
  [key: string]: never;
5
8
  }> implements AbstractControl<UnwrapValue<T>> {
@@ -170,10 +170,13 @@ class FormGroup {
170
170
  .querySelectorAll(`input[name="${this.name}"]:checked`)).values(),
171
171
  ];
172
172
  if (hasMultipleBindings > 1) {
173
- if (self.options.multi && this.type === 'checkbox') {
173
+ if ((self.options.multi || this.hasAttribute('multiple')) &&
174
+ this.type === 'checkbox') {
174
175
  value = inputsWithBindings.map((e) => e.value);
175
176
  }
176
- if (!self.options.multi && this.type === 'checkbox') {
177
+ if (!self.options.multi &&
178
+ !this.hasAttribute('multiple') &&
179
+ this.type === 'checkbox') {
177
180
  inputsWithBindings.forEach((el) => {
178
181
  if (el !== this)
179
182
  el.checked = false;
@@ -260,12 +263,15 @@ class FormGroup {
260
263
  const attr = customAttributes.find((a) => a.name.startsWith('#'));
261
264
  this.parentElement[attr.name.replace('#', '')] = el;
262
265
  }
263
- el.addEventListener('blur', () => __awaiter(this, void 0, void 0, function* () {
264
- this.setElementDirty(el);
265
- yield this.parentElement.requestUpdate();
266
- yield this.setElementValidity(el);
267
- }));
268
- el[strategy] = this.updateValueAndValidityOnEvent(el[strategy]);
266
+ if (!el._bound) {
267
+ el.addEventListener('blur', () => __awaiter(this, void 0, void 0, function* () {
268
+ this.setElementDirty(el);
269
+ yield this.parentElement.requestUpdate();
270
+ yield this.setElementValidity(el);
271
+ }));
272
+ el[strategy] = this.updateValueAndValidityOnEvent(el[strategy]);
273
+ el._bound = true;
274
+ }
269
275
  return el;
270
276
  });
271
277
  }
@@ -310,8 +316,11 @@ class FormGroup {
310
316
  validate(element) {
311
317
  return __awaiter(this, void 0, void 0, function* () {
312
318
  let errors = [];
313
- element.setCustomValidity('');
314
- if (!element.checkValidity()) {
319
+ if (typeof element.setCustomValidity === 'function') {
320
+ element.setCustomValidity('');
321
+ }
322
+ if (typeof element.checkValidity === 'function' &&
323
+ !element.checkValidity()) {
315
324
  return {
316
325
  errors: errors.concat(Object.keys(form_tokens_1.InputValidityState)
317
326
  .map((key) => element.validity[key]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rxdi/forms",
3
- "version": "0.7.230",
3
+ "version": "0.7.232",
4
4
  "main": "./dist/index.js",
5
5
  "author": "Kristiyan Tachev",
6
6
  "license": "MIT",
@@ -12,7 +12,7 @@
12
12
  "build": "tsc"
13
13
  },
14
14
  "devDependencies": {
15
- "@rxdi/lit-html": "^0.7.229",
15
+ "@rxdi/lit-html": "^0.7.231",
16
16
  "@types/node": "^25.0.3",
17
17
  "rxjs": "^7.8.2",
18
18
  "typescript": "^5.9.3"