@3kles/kles-material-dynamicforms 21.7.4 → 21.7.5

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.
@@ -4,7 +4,7 @@ import * as i1 from '@angular/common';
4
4
  import { CommonModule, AsyncPipe } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
6
6
  import { Validators, FormControl, ReactiveFormsModule, FormsModule, FormControlDirective, FormControlName, FormArray, FormGroup, UntypedFormBuilder, NG_VALUE_ACCESSOR, UntypedFormGroup } from '@angular/forms';
7
- import { concat, of, Subject, combineLatest, startWith, map as map$1, takeUntil, Observable, defer, distinctUntilChanged as distinctUntilChanged$1, filter as filter$1, switchMap as switchMap$1, timer, shareReplay as shareReplay$1, isObservable } from 'rxjs';
7
+ import { concat, of, Subject, combineLatest, startWith, map as map$1, takeUntil, Observable, defer, ReplaySubject, switchMap as switchMap$1, isObservable, timer, distinctUntilChanged as distinctUntilChanged$1, shareReplay as shareReplay$1 } from 'rxjs';
8
8
  import { tap, take, catchError, map, takeUntil as takeUntil$1, distinctUntilChanged, filter, switchMap, startWith as startWith$1, shareReplay, debounceTime, debounce } from 'rxjs/operators';
9
9
  import * as i3 from '@angular/material/form-field';
10
10
  import { MatError, MatFormFieldModule, MatFormField, MatHint, MatLabel, MatSuffix } from '@angular/material/form-field';
@@ -29,7 +29,7 @@ import { MatInputModule, MatInput, MatLabel as MatLabel$1, MatFormField as MatFo
29
29
  import * as i6 from '@angular/material/select';
30
30
  import { MatSelectModule, MatSelect, MatSelectTrigger } from '@angular/material/select';
31
31
  import { MatRadioModule, MatRadioButton, MatRadioGroup } from '@angular/material/radio';
32
- import * as i2$2 from '@angular/material/chips';
32
+ import * as i3$6 from '@angular/material/chips';
33
33
  import { MatChipsModule, MatChipOption, MatChipListbox } from '@angular/material/chips';
34
34
  import * as i4$1 from '@angular/material/tooltip';
35
35
  import { MatTooltipModule, MatTooltip } from '@angular/material/tooltip';
@@ -5338,208 +5338,311 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
5338
5338
  class KlesFormChipGridComponent extends KlesFieldAbstract {
5339
5339
  constructor() {
5340
5340
  super(...arguments);
5341
- this.options = this.field.options;
5342
5341
  this.control = this.group.controls[this.field.name];
5343
5342
  this.intl = inject(KlesDynamicFormIntl);
5344
5343
  this.separatorKeysCodes = [ENTER, COMMA];
5345
- this.isFocused = new Subject();
5346
- this.searchControl = new FormControl('aaa');
5344
+ /*
5345
+ * any est volontaire :
5346
+ * MatAutocomplete peut momentanément pousser l'objet
5347
+ * sélectionné dans le FormControl de recherche.
5348
+ */
5349
+ this.searchControl = new FormControl('', {
5350
+ nonNullable: true,
5351
+ });
5352
+ /*
5353
+ * ReplaySubject permet de ne pas perdre le premier focus
5354
+ * si l'Observable lazy n'est pas encore abonné.
5355
+ */
5356
+ this.loadOptions$ = new ReplaySubject(1);
5347
5357
  }
5348
5358
  ngOnInit() {
5349
- if (this.field.lazy) {
5350
- this.options$ = this.isFocused.pipe(distinctUntilChanged$1(), filter$1((isFocused) => isFocused), switchMap$1((isFocused) => {
5351
- if (isFocused) {
5352
- let obs$;
5353
- if (this.field.options instanceof Observable) {
5354
- obs$ = this.field.options;
5355
- }
5356
- else if (this.field.options instanceof Function) {
5357
- obs$ = this.field.options();
5358
- }
5359
- else {
5360
- obs$ = of(this.field.options ?? []);
5361
- }
5362
- return concat(of({ loading: true, options: [] }), obs$.pipe(map$1((options) => {
5363
- return { loading: false, options };
5364
- })));
5365
- }
5366
- else {
5367
- return of({ loading: false, options: [] });
5368
- }
5369
- }));
5370
- }
5371
- else {
5372
- if (this.field.options instanceof Observable) {
5373
- this.options$ = concat(of({ loading: true, options: [] }), this.field.options.pipe(map$1((options) => {
5374
- return { loading: false, options };
5375
- })));
5376
- }
5377
- else if (this.field.options instanceof Function) {
5378
- this.options$ = concat(of({ loading: true, options: [] }), this.field.options().pipe(map$1((options) => {
5379
- return { loading: false, options };
5380
- })));
5381
- }
5382
- else {
5383
- this.options$ = of({ loading: false, options: this.field.options });
5384
- }
5385
- }
5386
- this.filteredOption$ = concat(combineLatest([this.searchControl?.valueChanges.pipe(startWith('')) ?? of(''), this.options$]).pipe(map$1(([data, response]) => {
5359
+ this.options$ = this.createOptionsStream();
5360
+ this.filteredOption$ = combineLatest([this.searchControl.valueChanges.pipe(startWith(this.searchControl.value)), this.options$, this.control.valueChanges.pipe(startWith(this.control.value ?? []))]).pipe(map$1(([search, response, selectedValues]) => {
5387
5361
  if (response.loading) {
5388
5362
  return response;
5389
5363
  }
5390
- else {
5391
- return { loading: false, options: data && response.options ? this.filterData(data, response.options) : response.options };
5364
+ const selected = Array.isArray(selectedValues) ? selectedValues : [];
5365
+ /*
5366
+ * On retire de la liste les options
5367
+ * déjà présentes dans les chips.
5368
+ */
5369
+ let options = response.options.filter((option) => !selected.some((selectedValue) => this.isSameOption(option, selectedValue)));
5370
+ /*
5371
+ * Le contrôle peut momentanément contenir
5372
+ * un objet pendant une sélection autocomplete.
5373
+ */
5374
+ if (typeof search === 'string' && search.trim()) {
5375
+ options = this.filterData(search, options);
5392
5376
  }
5393
- })));
5377
+ return {
5378
+ loading: false,
5379
+ options,
5380
+ };
5381
+ }));
5394
5382
  super.ngOnInit();
5395
5383
  }
5396
- ngOnDestroy() {
5397
- super.ngOnDestroy();
5398
- }
5399
5384
  onFocus() {
5400
5385
  if (this.field.lazy) {
5401
- this.isFocused.next(true);
5386
+ this.loadOptions$.next();
5402
5387
  }
5403
5388
  super.onFocus();
5404
5389
  }
5405
5390
  onTokenEnd(event) {
5406
- this.addChip(event.value);
5391
+ /*
5392
+ * Quand property est renseignée, les valeurs sont
5393
+ * considérées comme des objets provenant de l'autocomplete.
5394
+ *
5395
+ * On évite donc d'ajouter une string libre au tableau.
5396
+ */
5397
+ if (this.field.property) {
5398
+ return;
5399
+ }
5400
+ const value = event.value.trim();
5401
+ if (!value) {
5402
+ return;
5403
+ }
5404
+ this.addChip(value);
5407
5405
  event.chipInput.clear();
5406
+ this.searchControl.setValue('');
5408
5407
  }
5409
- addChip(rawValue) {
5410
- const value = (rawValue || '').trim();
5411
- if (value) {
5412
- this.control.setValue([...(this.control.value ?? []), value]);
5408
+ addChip(value) {
5409
+ if (value === null || value === undefined || value === '') {
5410
+ return;
5411
+ }
5412
+ const values = Array.isArray(this.control.value) ? this.control.value : [];
5413
+ /*
5414
+ * Empêche d'ajouter deux fois la même valeur.
5415
+ */
5416
+ const exists = values.some((currentValue) => this.isSameOption(currentValue, value));
5417
+ if (exists) {
5418
+ return;
5413
5419
  }
5420
+ this.control.setValue([...values, value]);
5421
+ this.control.markAsDirty();
5414
5422
  }
5415
5423
  removeChip(value) {
5416
- const values = this.control.value;
5417
- const index = values.lastIndexOf(value);
5418
- if (index > -1) {
5419
- values.splice(index, 1);
5420
- this.control.setValue(values);
5424
+ const values = Array.isArray(this.control.value) ? [...this.control.value] : [];
5425
+ const index = values.findIndex((currentValue) => this.isSameOption(currentValue, value));
5426
+ if (index === -1) {
5427
+ return;
5421
5428
  }
5429
+ values.splice(index, 1);
5430
+ this.control.setValue(values);
5431
+ this.control.markAsDirty();
5422
5432
  }
5423
- selected(event) {
5424
- this.addChip(event.option.viewValue);
5433
+ selected(event, chipInput) {
5434
+ const value = event.option.value;
5435
+ /*
5436
+ * On ajoute d'abord l'objet sélectionné aux chips.
5437
+ */
5438
+ this.addChip(value);
5439
+ /*
5440
+ * L'autocomplete n'est ici qu'une source de sélection.
5441
+ * La sélection réelle est représentée par les chips.
5442
+ */
5425
5443
  event.option.deselect();
5426
- this.searchControl.reset();
5444
+ /*
5445
+ * Important :
5446
+ * MatChipInput.clear() nettoie réellement l'input HTML.
5447
+ */
5448
+ chipInput.clear();
5449
+ /*
5450
+ * Et on synchronise le FormControl afin de :
5451
+ * - vider l'état Angular ;
5452
+ * - supprimer le filtre ;
5453
+ * - recalculer filteredOption$.
5454
+ */
5455
+ this.searchControl.setValue('');
5427
5456
  }
5428
- filterData(value, options) {
5429
- let filterValue = undefined;
5430
- const property = this.field.property;
5431
- if (typeof value === 'string' && Object.prototype.toString.call(value) === '[object String]') {
5432
- filterValue = value.toLowerCase();
5457
+ displayValue(value) {
5458
+ if (value === null || value === undefined) {
5459
+ return '';
5433
5460
  }
5434
- else {
5435
- if (property) {
5436
- filterValue = value[property]?.toLowerCase();
5437
- }
5461
+ if (this.field.property) {
5462
+ return value?.[this.field.property] ?? '';
5438
5463
  }
5439
- if (filterValue != undefined) {
5440
- if (property) {
5441
- return options.filter((option) => option[property].toLowerCase().indexOf(filterValue) === 0);
5442
- }
5443
- return options.filter((option) => option.toLowerCase().indexOf(filterValue) === 0);
5464
+ return value;
5465
+ }
5466
+ createOptionsStream() {
5467
+ /*
5468
+ * Lazy :
5469
+ * recharge les options à chaque focus.
5470
+ */
5471
+ if (this.field.lazy) {
5472
+ return this.loadOptions$.pipe(switchMap$1(() => concat(of({
5473
+ loading: true,
5474
+ options: [],
5475
+ }), this.resolveOptions().pipe(map$1((options) => ({
5476
+ loading: false,
5477
+ options,
5478
+ }))))));
5444
5479
  }
5445
- else {
5480
+ /*
5481
+ * Liste statique :
5482
+ * aucun chargement à afficher.
5483
+ */
5484
+ if (Array.isArray(this.field.options)) {
5485
+ return of({
5486
+ loading: false,
5487
+ options: this.field.options,
5488
+ });
5489
+ }
5490
+ /*
5491
+ * Observable ou fonction :
5492
+ * spinner jusqu'à réception des options.
5493
+ */
5494
+ return concat(of({
5495
+ loading: true,
5496
+ options: [],
5497
+ }), this.resolveOptions().pipe(map$1((options) => ({
5498
+ loading: false,
5499
+ options,
5500
+ }))));
5501
+ }
5502
+ resolveOptions() {
5503
+ const source = typeof this.field.options === 'function' ? this.field.options() : this.field.options;
5504
+ if (isObservable(source)) {
5505
+ return source;
5506
+ }
5507
+ return of(source ?? []);
5508
+ }
5509
+ filterData(search, options) {
5510
+ if (typeof search !== 'string') {
5511
+ return options;
5512
+ }
5513
+ const filterValue = search.trim().toLowerCase();
5514
+ if (!filterValue) {
5446
5515
  return options;
5447
5516
  }
5517
+ return options.filter((option) => {
5518
+ const value = this.displayValue(option);
5519
+ return String(value ?? '')
5520
+ .toLowerCase()
5521
+ .startsWith(filterValue);
5522
+ });
5523
+ }
5524
+ isSameOption(a, b) {
5525
+ /*
5526
+ * Primitive identique ou même référence objet.
5527
+ */
5528
+ if (a === b) {
5529
+ return true;
5530
+ }
5531
+ /*
5532
+ * En mode objet, property sert actuellement
5533
+ * également à identifier les doublons.
5534
+ */
5535
+ if (this.field.property && a !== null && a !== undefined && b !== null && b !== undefined) {
5536
+ return a[this.field.property] === b[this.field.property];
5537
+ }
5538
+ return false;
5448
5539
  }
5449
5540
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: KlesFormChipGridComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5450
5541
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: KlesFormChipGridComponent, isStandalone: true, selector: "kles-form-chip-grid", usesInheritance: true, ngImport: i0, template: `
5451
5542
  <mat-form-field [formGroup]="group" [matTooltip]="tooltip()" [appearance]="appearance()">
5452
5543
  <mat-label>{{ label() }}</mat-label>
5453
- <mat-chip-grid #reactiveChipGrid [formControl]="group.controls[field.name]">
5454
- @for (value of group.controls[field.name].value ?? []; track value) {
5455
- <mat-chip-row (removed)="removeChip(value)">
5456
- {{ (field.property ? value[field.property] : value) | klesTransform: field.pipeTransform }}
5544
+
5545
+ <mat-chip-grid #reactiveChipGrid [formControl]="control">
5546
+ @for (value of control.value ?? []; track $index) {
5547
+ <mat-chip-row [value]="value" (removed)="removeChip(value)">
5548
+ {{ displayValue(value) | klesTransform: field.pipeTransform }}
5549
+
5457
5550
  <button matChipRemove>
5458
5551
  <mat-icon>cancel</mat-icon>
5459
5552
  </button>
5460
5553
  </mat-chip-row>
5461
5554
  }
5462
5555
  </mat-chip-grid>
5556
+
5463
5557
  <input
5464
- #search
5558
+ #chipInput="matChipInput"
5465
5559
  [formControl]="searchControl"
5466
5560
  [placeholder]="placeholder()"
5467
5561
  [matChipInputFor]="reactiveChipGrid"
5468
- (matChipInputTokenEnd)="onTokenEnd($event)"
5469
5562
  [matAutocomplete]="auto"
5470
5563
  [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
5564
+ (matChipInputTokenEnd)="onTokenEnd($event)"
5471
5565
  (focus)="onFocus()"
5472
5566
  (blur)="onBlur()"
5473
5567
  />
5474
5568
 
5475
- <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event); search.value = ''">
5569
+ <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event, chipInput)">
5476
5570
  @if (filteredOption$ | async; as filteredOption) {
5477
5571
  @if (filteredOption.loading) {
5478
5572
  <mat-option disabled>
5479
5573
  <div class="loadingSelect">
5480
5574
  {{ intl.loading }}...
5481
- <mat-spinner class="spinner" diameter="20"></mat-spinner>
5575
+
5576
+ <mat-spinner class="spinner" diameter="20" />
5482
5577
  </div>
5483
5578
  </mat-option>
5484
5579
  } @else {
5485
5580
  @for (item of filteredOption.options; track item) {
5486
- <mat-option [value]="item" [disabled]="item?.disabled">{{ (field.property ? item[field.property] : item) | klesTransform: field.pipeTransform }}</mat-option>
5581
+ <mat-option [value]="item" [disabled]="item?.disabled">
5582
+ {{ displayValue(item) | klesTransform: field.pipeTransform }}
5583
+ </mat-option>
5487
5584
  }
5488
5585
  }
5489
5586
  }
5490
5587
  </mat-autocomplete>
5491
5588
 
5492
- <mat-error matErrorMessage [validations]="field.validations" [asyncValidations]="field.asyncValidations"></mat-error>
5589
+ <mat-error matErrorMessage [validations]="field.validations" [asyncValidations]="field.asyncValidations" />
5493
5590
  </mat-form-field>
5494
- `, isInline: true, styles: [".suffix{display:flex;align-items:center}\n", ".field-bottom .mat-mdc-form-field-bottom-align:before{content:none!important}\n", ".loadingSelect{display:flex;flex-direction:row;justify-content:space-between;align-items:center}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2$2.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i2$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "directive", type: i2$2.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i2$2.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: MatErrorMessageDirective, selector: "[matErrorMessage]", inputs: ["validations", "asyncValidations"] }, { kind: "pipe", type: KlesTransformPipe, name: "klesTransform" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
5591
+ `, isInline: true, styles: [".suffix{display:flex;align-items:center}\n", ".field-bottom .mat-mdc-form-field-bottom-align:before{content:none!important}\n", ".loadingSelect{display:flex;flex-direction:row;justify-content:space-between;align-items:center}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i3$6.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i3$6.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "directive", type: i3$6.MatChipRemove, selector: "[matChipRemove]" }, { kind: "component", type: i3$6.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: MatErrorMessageDirective, selector: "[matErrorMessage]", inputs: ["validations", "asyncValidations"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: KlesTransformPipe, name: "klesTransform" }] }); }
5495
5592
  }
5496
5593
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: KlesFormChipGridComponent, decorators: [{
5497
5594
  type: Component,
5498
5595
  args: [{ selector: 'kles-form-chip-grid', template: `
5499
5596
  <mat-form-field [formGroup]="group" [matTooltip]="tooltip()" [appearance]="appearance()">
5500
5597
  <mat-label>{{ label() }}</mat-label>
5501
- <mat-chip-grid #reactiveChipGrid [formControl]="group.controls[field.name]">
5502
- @for (value of group.controls[field.name].value ?? []; track value) {
5503
- <mat-chip-row (removed)="removeChip(value)">
5504
- {{ (field.property ? value[field.property] : value) | klesTransform: field.pipeTransform }}
5598
+
5599
+ <mat-chip-grid #reactiveChipGrid [formControl]="control">
5600
+ @for (value of control.value ?? []; track $index) {
5601
+ <mat-chip-row [value]="value" (removed)="removeChip(value)">
5602
+ {{ displayValue(value) | klesTransform: field.pipeTransform }}
5603
+
5505
5604
  <button matChipRemove>
5506
5605
  <mat-icon>cancel</mat-icon>
5507
5606
  </button>
5508
5607
  </mat-chip-row>
5509
5608
  }
5510
5609
  </mat-chip-grid>
5610
+
5511
5611
  <input
5512
- #search
5612
+ #chipInput="matChipInput"
5513
5613
  [formControl]="searchControl"
5514
5614
  [placeholder]="placeholder()"
5515
5615
  [matChipInputFor]="reactiveChipGrid"
5516
- (matChipInputTokenEnd)="onTokenEnd($event)"
5517
5616
  [matAutocomplete]="auto"
5518
5617
  [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
5618
+ (matChipInputTokenEnd)="onTokenEnd($event)"
5519
5619
  (focus)="onFocus()"
5520
5620
  (blur)="onBlur()"
5521
5621
  />
5522
5622
 
5523
- <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event); search.value = ''">
5623
+ <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event, chipInput)">
5524
5624
  @if (filteredOption$ | async; as filteredOption) {
5525
5625
  @if (filteredOption.loading) {
5526
5626
  <mat-option disabled>
5527
5627
  <div class="loadingSelect">
5528
5628
  {{ intl.loading }}...
5529
- <mat-spinner class="spinner" diameter="20"></mat-spinner>
5629
+
5630
+ <mat-spinner class="spinner" diameter="20" />
5530
5631
  </div>
5531
5632
  </mat-option>
5532
5633
  } @else {
5533
5634
  @for (item of filteredOption.options; track item) {
5534
- <mat-option [value]="item" [disabled]="item?.disabled">{{ (field.property ? item[field.property] : item) | klesTransform: field.pipeTransform }}</mat-option>
5635
+ <mat-option [value]="item" [disabled]="item?.disabled">
5636
+ {{ displayValue(item) | klesTransform: field.pipeTransform }}
5637
+ </mat-option>
5535
5638
  }
5536
5639
  }
5537
5640
  }
5538
5641
  </mat-autocomplete>
5539
5642
 
5540
- <mat-error matErrorMessage [validations]="field.validations" [asyncValidations]="field.asyncValidations"></mat-error>
5643
+ <mat-error matErrorMessage [validations]="field.validations" [asyncValidations]="field.asyncValidations" />
5541
5644
  </mat-form-field>
5542
- `, standalone: true, imports: [MatIconModule, KlesTransformPipe, MatChipsModule, MatTooltip, ReactiveFormsModule, MatFormFieldModule, MatAutocompleteModule, AsyncPipe, MatProgressSpinnerModule, MatError, MatErrorMessageDirective], styles: [".suffix{display:flex;align-items:center}\n", ".field-bottom .mat-mdc-form-field-bottom-align:before{content:none!important}\n", ".loadingSelect{display:flex;flex-direction:row;justify-content:space-between;align-items:center}\n", "mat-form-field{width:100%}\n"] }]
5645
+ `, standalone: true, imports: [AsyncPipe, KlesTransformPipe, MatAutocompleteModule, MatChipsModule, MatError, MatErrorMessageDirective, MatFormFieldModule, MatIconModule, MatProgressSpinnerModule, MatTooltip, ReactiveFormsModule], styles: [".suffix{display:flex;align-items:center}\n", ".field-bottom .mat-mdc-form-field-bottom-align:before{content:none!important}\n", ".loadingSelect{display:flex;flex-direction:row;justify-content:space-between;align-items:center}\n", "mat-form-field{width:100%}\n"] }]
5543
5646
  }] });
5544
5647
 
5545
5648
  const components = [