@sumaris-net/ngx-components 1.5.11 → 1.6.3

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.
Files changed (30) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +568 -216
  2. package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
  3. package/bundles/sumaris-net.ngx-components.umd.min.js +2 -2
  4. package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
  5. package/doc/changelog.md +7 -0
  6. package/esm2015/src/app/core/auth/modal/modal-auth.js +21 -9
  7. package/esm2015/src/app/core/form/editor.class.js +17 -3
  8. package/esm2015/src/app/core/form/form.class.js +6 -5
  9. package/esm2015/src/app/core/table/entities-table-datasource.class.js +35 -1
  10. package/esm2015/src/app/core/table/table.class.js +7 -2
  11. package/esm2015/src/app/shared/form/field.model.js +1 -1
  12. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +81 -88
  13. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +2 -2
  14. package/esm2015/src/app/shared/material/chips/material.chips.js +336 -79
  15. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +7 -4
  16. package/esm2015/src/app/shared/material/swipe/material.swipe.js +5 -5
  17. package/esm2015/src/app/shared/material/swipe/testing/swipe.test.js +2 -2
  18. package/esm2015/src/app/shared/observables.js +10 -3
  19. package/fesm2015/sumaris-net.ngx-components.js +512 -188
  20. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/app/core/auth/modal/modal-auth.d.ts +12 -5
  23. package/src/app/core/form/editor.class.d.ts +9 -1
  24. package/src/app/core/table/entities-table-datasource.class.d.ts +6 -1
  25. package/src/app/shared/form/field.model.d.ts +2 -1
  26. package/src/app/shared/material/autocomplete/material.autocomplete.d.ts +35 -35
  27. package/src/app/shared/material/chips/material.chips.d.ts +35 -10
  28. package/src/app/shared/material/swipe/material.swipe.d.ts +2 -2
  29. package/src/app/shared/observables.d.ts +2 -0
  30. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, EventEmitter, forwardRef, Component, ChangeDetectionStrategy, ChangeDetectorRef, Optional, Input, HostBinding, Output, ViewChild, Pipe, Injectable, Directive, Inject, NgModule, ElementRef, ViewChildren, HostListener, ComponentFactoryResolver, ApplicationRef, Injector, Renderer2 } from '@angular/core';
2
+ import { InjectionToken, EventEmitter, Component, forwardRef, ChangeDetectionStrategy, ChangeDetectorRef, Optional, Input, Output, ViewChild, HostBinding, Pipe, Injectable, Directive, Inject, NgModule, ElementRef, ViewChildren, HostListener, ComponentFactoryResolver, ApplicationRef, Injector, Renderer2 } from '@angular/core';
3
3
  import * as i1$3 from '@angular/common';
4
4
  import { CommonModule, DOCUMENT, Location } from '@angular/common';
5
5
  import { CdkTableModule } from '@angular/cdk/table';
@@ -36,7 +36,7 @@ import { MatAutocomplete, MatAutocompleteTrigger, MatAutocompleteModule, MAT_AUT
36
36
  import { __awaiter, __decorate } from 'tslib';
37
37
  import * as i1$6 from '@angular/forms';
38
38
  import { NG_VALUE_ACCESSOR, FormGroupDirective, AbstractControl, FormGroup, FormArray, FormControl, ReactiveFormsModule, Validators, FormBuilder } from '@angular/forms';
39
- import { timer, merge, fromEvent, Subscription, BehaviorSubject, Subject, isObservable, noop as noop$8, Observable, defer, of, from, combineLatest, EMPTY } from 'rxjs';
39
+ import { timer, merge, fromEvent, BehaviorSubject, Subscription, Subject, isObservable, noop as noop$8, Observable, defer, of, from, combineLatest, EMPTY } from 'rxjs';
40
40
  import { filter, first, map, takeUntil, switchMap, startWith, debounceTime, takeWhile, tap, distinctUntilChanged, mergeMap, catchError, throttleTime, skip } from 'rxjs/operators';
41
41
  import * as i1$1 from '@ngx-translate/core';
42
42
  import { TranslateService, TranslateModule } from '@ngx-translate/core';
@@ -843,6 +843,14 @@ function chainPromises(defers) {
843
843
  .then(jobRes => finalResult.concat(jobRes)));
844
844
  }, null);
845
845
  }
846
+ function firstTrue(obs) {
847
+ return obs.pipe(first((v) => v === true), map(_ => { }) // Convert to void
848
+ );
849
+ }
850
+ function firstFalse(obs) {
851
+ return obs.pipe(first((v) => v === false), map(_ => { }) // Convert to void
852
+ );
853
+ }
846
854
  /**
847
855
  * Wait form a predicate return true. This need to implement AppFormUtils.waitWhilePending(), AppFormUtils.waitIdle()
848
856
  * @param predicate
@@ -872,8 +880,7 @@ function waitFor(predicate, opts) {
872
880
  }
873
881
  function waitForTrue(observable, opts) {
874
882
  return __awaiter(this, void 0, void 0, function* () {
875
- const firstTrueObservable = observable.pipe(first((v) => v === true), map(() => { }) // convert to void
876
- );
883
+ const firstTrueObservable = firstTrue(observable);
877
884
  // Timeout (+ dueTime)
878
885
  if (opts && opts.timeout > 0) {
879
886
  const $timeout = timer(opts.timeout);
@@ -969,11 +976,10 @@ class MatAutocompleteConfigHolder {
969
976
  const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
970
977
  const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
971
978
  const displayWith = options.displayWith || ((obj) => obj && joinPropertiesPath(obj, attributes));
972
- const compareWith = options.compareWith || ((o1, o2) => o1 && o2 && o1.id === o2.id);
979
+ const compareWith = options.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
973
980
  const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
974
981
  filter,
975
- displayWith,
976
- compareWith });
982
+ displayWith, equals: compareWith });
977
983
  this.fields[fieldName] = config;
978
984
  return config;
979
985
  }
@@ -984,11 +990,6 @@ class MatAutocompleteConfigHolder {
984
990
  return this.fields[fieldName] || this.add(fieldName);
985
991
  }
986
992
  }
987
- const DEFAULT_VALUE_ACCESSOR$6 = {
988
- provide: NG_VALUE_ACCESSOR,
989
- useExisting: forwardRef(() => MatAutocompleteField),
990
- multi: true
991
- };
992
993
  const noop$7 = () => { };
993
994
  const ɵ0$a = noop$7;
994
995
  class MatAutocompleteField {
@@ -997,14 +998,6 @@ class MatAutocompleteField {
997
998
  this.formGroupDir = formGroupDir;
998
999
  this._onChangeCallback = noop$7;
999
1000
  this._onTouchedCallback = noop$7;
1000
- this._subscription = new Subscription();
1001
- this._filter$ = new BehaviorSubject(undefined);
1002
- this._reload$ = new Subject();
1003
- this._readonly = false;
1004
- this.$inputItems = new BehaviorSubject(undefined);
1005
- this.$filteredItems = new BehaviorSubject(undefined);
1006
- this.displayValue = '';
1007
- this._fetchMore$ = new EventEmitter();
1008
1001
  this.logPrefix = '[mat-autocomplete] ';
1009
1002
  this.formControlName = null;
1010
1003
  this.required = false;
@@ -1017,13 +1010,21 @@ class MatAutocompleteField {
1017
1010
  this.fetchMoreThreshold = '15%';
1018
1011
  this.suggestLengthThreshold = null;
1019
1012
  this.showLoadingSpinner = true;
1013
+ this.clicked = new EventEmitter();
1014
+ this.blurred = new EventEmitter();
1015
+ this.focused = new EventEmitter();
1016
+ this.dropButtonClick = new EventEmitter(true);
1017
+ this.keydownEscape = new EventEmitter();
1018
+ this.keyupEnter = new EventEmitter();
1020
1019
  this.animationsDisabled = true;
1021
- this.onClick = new EventEmitter();
1022
- this.onBlur = new EventEmitter();
1023
- this.onFocus = new EventEmitter();
1024
- this.onDropButtonClick = new EventEmitter(true);
1025
- this.onKeydownEscape = new EventEmitter();
1026
- this.onKeyupEnter = new EventEmitter();
1020
+ this._readonly = false;
1021
+ this.$inputItems = new BehaviorSubject(undefined);
1022
+ this.$filteredItems = new BehaviorSubject(undefined);
1023
+ this.displayValue = '';
1024
+ this._fetchMore$ = new EventEmitter();
1025
+ this._subscription = new Subscription();
1026
+ this._$filter = new BehaviorSubject(undefined);
1027
+ this._reload$ = new Subject();
1027
1028
  }
1028
1029
  get itemCount() {
1029
1030
  return this._itemCount;
@@ -1032,14 +1033,14 @@ class MatAutocompleteField {
1032
1033
  return this._onFetchMoreCallback && this._moreItemsCount > 0;
1033
1034
  }
1034
1035
  set filter(value) {
1035
- if (value !== this._filter$.value) {
1036
+ if (value !== this._$filter.value) {
1036
1037
  // DEBUG
1037
1038
  //console.debug(this.logPrefix + " Setting filter:", value);
1038
- this._filter$.next(value);
1039
+ this._$filter.next(value);
1039
1040
  }
1040
1041
  }
1041
1042
  get filter() {
1042
- return this._filter$.value;
1043
+ return this._$filter.value;
1043
1044
  }
1044
1045
  set readonly(value) {
1045
1046
  this._readonly = value;
@@ -1102,6 +1103,7 @@ class MatAutocompleteField {
1102
1103
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
1103
1104
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
1104
1105
  this.displayWith = this.displayWith || this.config.displayWith;
1106
+ this.equals = this.equals || this.config.equals;
1105
1107
  this.mobile = toBoolean(this.mobile, this.config.mobile);
1106
1108
  this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
1107
1109
  this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
@@ -1116,20 +1118,18 @@ class MatAutocompleteField {
1116
1118
  this.displayColumnSizes = this.displayColumnSizes
1117
1119
  // if only column: auto size
1118
1120
  || (this.displayAttributes.length === 1 && [undefined])
1119
- || this.displayAttributes.map(attr =>
1120
- // If label, set col size = 2
1121
- (attr && attr.endsWith('label')) ? 2 :
1122
- // If rankOrder => col size = 1
1123
- ((attr && attr.endsWith('rankOrder')) ? 1
1124
- // Else => auto size
1121
+ // Computed column size:
1122
+ // - if label then col size = 2
1123
+ // - if rankOrder then col size = 1
1124
+ // - ese => auto size
1125
+ || this.displayAttributes.map(attr => (attr && attr.endsWith('label')) ? 2
1126
+ : ((attr && attr.endsWith('rankOrder')) ? 1
1125
1127
  : undefined));
1126
1128
  this.displayColumnNames = this.displayAttributes.map((attr, index) => this.displayColumnNames && this.displayColumnNames[index] ||
1127
1129
  (this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()));
1128
1130
  this.mobile = toBoolean(this.mobile, false);
1129
1131
  this.searchable = !this.mobile && !this.multiple;
1130
- // Default comparator (only need when using mat-select)
1131
- if (!this.searchable && !this.compareWith)
1132
- this.compareWith = (o1, o2) => o1 && o2 && o1.id === o2.id;
1132
+ this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
1133
1133
  const classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
1134
1134
  this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
1135
1135
  || (classList.includes('min-width-large') && '400px')
@@ -1144,7 +1144,7 @@ class MatAutocompleteField {
1144
1144
  if (!this.suggestFn) {
1145
1145
  const suggestFromArrayFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
1146
1146
  // DEBUG
1147
- //console.debug(this.logPrefix + " Calling suggestFromArray with value=", value);
1147
+ //console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
1148
1148
  return suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter));
1149
1149
  });
1150
1150
  // Wait (once) that items are loaded, then call suggest from array fn
@@ -1162,7 +1162,7 @@ class MatAutocompleteField {
1162
1162
  }
1163
1163
  else if (!this.searchable) {
1164
1164
  // Manually fill input items, from the given suggest function
1165
- this._subscription.add(this._filter$.pipe(startWith(this.filter), debounceTime(250), takeWhile((_) => !this.searchable), // Close subscription, when enabling search (no more mat-select)
1165
+ this._subscription.add(this._$filter.pipe(startWith(this.filter), debounceTime(250), takeWhile((_) => !this.searchable), // Close subscription, when enabling search (no more mat-select)
1166
1166
  switchMap((filter) => this.suggest('*', filter)))
1167
1167
  .subscribe(items => this.$inputItems.next(items)));
1168
1168
  }
@@ -1173,11 +1173,7 @@ class MatAutocompleteField {
1173
1173
  this.formControl.valueChanges
1174
1174
  .pipe(filter(value => this.enabled && this.searchable && isNotNilString(value)),
1175
1175
  // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
1176
- tap(value => {
1177
- if (this.showLoadingSpinner) {
1178
- this.markAsLoading();
1179
- }
1180
- }),
1176
+ tap(_ => this.showLoadingSpinner && this.markAsLoading()),
1181
1177
  // Filter if not enough character
1182
1178
  filter(value => value.length >= this.suggestLengthThreshold),
1183
1179
  // Wait a debounce time
@@ -1206,12 +1202,12 @@ class MatAutocompleteField {
1206
1202
  // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
1207
1203
  merge(
1208
1204
  // Focus or click => Load all
1209
- merge(this.onFocus, this.onClick)
1205
+ merge(this.focused, this.clicked)
1210
1206
  .pipe(filter(_ => this.enabled && this.searchable), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)),
1211
1207
  // On dropdown button click
1212
- this.onDropButtonClick
1213
- .pipe(filter(event => this.enabled && this.searchable && (!event || !event.defaultPrevented)), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)), merge(this.$inputItems, this._filter$)
1214
- .pipe(filter(event => this.enabled && this.searchable), map(_ => this.formControl.value)))
1208
+ this.dropButtonClick
1209
+ .pipe(filter(event => this.searchable && this.enabled && (!event || !event.defaultPrevented)), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)), merge(this.$inputItems, this._$filter)
1210
+ .pipe(filter(_ => this.searchable && this.enabled), map(_ => this.formControl.value)))
1215
1211
  .pipe(
1216
1212
  // Start to suggest when :
1217
1213
  // - '*'
@@ -1250,7 +1246,7 @@ class MatAutocompleteField {
1250
1246
  // Make sure control value is inside (mat-select)
1251
1247
  if (items && !this.searchable) {
1252
1248
  const value = this.formControl.value;
1253
- if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.compareWith(item, value)) === -1) {
1249
+ if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.equals(item, value)) === -1) {
1254
1250
  // If form value is missing: add it to the list
1255
1251
  items = items.concat(value);
1256
1252
  }
@@ -1259,7 +1255,7 @@ class MatAutocompleteField {
1259
1255
  this.$filteredItems.next(items);
1260
1256
  }));
1261
1257
  // Applying implicit value, on blur
1262
- this._subscription.add(this.onBlur
1258
+ this._subscription.add(this.blurred
1263
1259
  .pipe(
1264
1260
  // Skip if not searchable
1265
1261
  filter(_ => this.searchable), map(_ => this.formControl.value))
@@ -1289,7 +1285,7 @@ class MatAutocompleteField {
1289
1285
  distinctUntilChanged())
1290
1286
  // Update component state
1291
1287
  .subscribe(() => this.checkIfTouched()));
1292
- this._subscription.add(this.onKeydownEscape.subscribe(event => {
1288
+ this._subscription.add(this.keydownEscape.subscribe(event => {
1293
1289
  if (this.isOpen) {
1294
1290
  event === null || event === void 0 ? void 0 : event.stopPropagation();
1295
1291
  event === null || event === void 0 ? void 0 : event.preventDefault();
@@ -1310,18 +1306,18 @@ class MatAutocompleteField {
1310
1306
  this.$inputItems.complete();
1311
1307
  this.$filteredItems.complete();
1312
1308
  this._reload$.complete();
1313
- this._filter$.complete();
1314
- this.onDropButtonClick.complete();
1315
- this.onClick.complete();
1316
- this.onBlur.complete();
1317
- this.onFocus.complete();
1318
- this.onKeydownEscape.complete();
1319
- this.onKeyupEnter.complete();
1309
+ this._$filter.complete();
1310
+ this.dropButtonClick.complete();
1311
+ this.clicked.complete();
1312
+ this.blurred.complete();
1313
+ this.focused.complete();
1314
+ this.keydownEscape.complete();
1315
+ this.keyupEnter.complete();
1320
1316
  this._fetchMore$.complete();
1321
1317
  this._implicitValue = undefined;
1322
1318
  this.formControl = null;
1323
1319
  this.displayWith = null;
1324
- this.compareWith = null;
1320
+ this.equals = null;
1325
1321
  this.suggestFn = null;
1326
1322
  this.$filteredItems = null;
1327
1323
  this.matSelectItems$ = null;
@@ -1331,8 +1327,8 @@ class MatAutocompleteField {
1331
1327
  this._onTouchedCallback = null;
1332
1328
  this._onFetchMoreCallback = null;
1333
1329
  // Destroy the 'autocomplete' instance, to avoid memory leak
1334
- if (this.matAutocomplete) {
1335
- this.matAutocomplete.ngOnDestroy();
1330
+ if (this.autocomplete) {
1331
+ this.autocomplete.ngOnDestroy();
1336
1332
  }
1337
1333
  }
1338
1334
  /**
@@ -1358,7 +1354,7 @@ class MatAutocompleteField {
1358
1354
  }
1359
1355
  setDisabledState(isDisabled) {
1360
1356
  var _a;
1361
- if (isDisabled && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1357
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1362
1358
  this.closePanel();
1363
1359
  }
1364
1360
  this.cd.markForCheck();
@@ -1372,7 +1368,7 @@ class MatAutocompleteField {
1372
1368
  (_a = this.matSelect) === null || _a === void 0 ? void 0 : _a.focus();
1373
1369
  }
1374
1370
  }
1375
- filterInputTextFocusInEvent(event) {
1371
+ filterInputTextFocusEvent(event) {
1376
1372
  if (!event || event.defaultPrevented)
1377
1373
  return;
1378
1374
  // Ignore event from mat-option
@@ -1381,7 +1377,7 @@ class MatAutocompleteField {
1381
1377
  if (event.stopPropagation)
1382
1378
  event.stopPropagation();
1383
1379
  event.returnValue = false;
1384
- //DEBUG console.debug(this.logPrefix + " Cancelling focus event");
1380
+ //DEBUG console.debug(this.logPrefix + ' Cancelling focus event');
1385
1381
  return false;
1386
1382
  }
1387
1383
  const hasContent = selectInputContent(event);
@@ -1389,7 +1385,7 @@ class MatAutocompleteField {
1389
1385
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
1390
1386
  // DEBUG
1391
1387
  //console.debug(this.logPrefix + ' Emit focus event');
1392
- this.onFocus.emit(event);
1388
+ this.focused.emit(event);
1393
1389
  return true;
1394
1390
  }
1395
1391
  return false;
@@ -1410,7 +1406,7 @@ class MatAutocompleteField {
1410
1406
  //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
1411
1407
  // Move caret to the beginning (fix issue IMAGINE-469)
1412
1408
  selectInputRange(event.target, 0, 0);
1413
- this.onBlur.emit(event);
1409
+ this.blurred.emit(event);
1414
1410
  return true;
1415
1411
  }
1416
1412
  filterMatSelectFocusEvent(event) {
@@ -1418,7 +1414,7 @@ class MatAutocompleteField {
1418
1414
  return;
1419
1415
  // DEBUG
1420
1416
  // console.debug(this.logPrefix + " Received <mat-select> focus event", event);
1421
- this.onFocus.emit(event);
1417
+ this.focused.emit(event);
1422
1418
  }
1423
1419
  filterMatSelectBlurEvent(event) {
1424
1420
  if (!event || event.defaultPrevented)
@@ -1435,7 +1431,7 @@ class MatAutocompleteField {
1435
1431
  // console.debug(this.logPrefix + " Cancelling <mat-select> blur event");
1436
1432
  return false;
1437
1433
  }
1438
- this.onBlur.emit(event);
1434
+ this.blurred.emit(event);
1439
1435
  return true;
1440
1436
  }
1441
1437
  toggleSearch(event) {
@@ -1457,7 +1453,7 @@ class MatAutocompleteField {
1457
1453
  event.stopPropagation();
1458
1454
  }
1459
1455
  _initAutocompleteInfiniteScroll(threshold) {
1460
- if (!this.matAutocomplete)
1456
+ if (!this.autocomplete)
1461
1457
  return; // Skip
1462
1458
  // DEBUG
1463
1459
  //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
@@ -1465,12 +1461,12 @@ class MatAutocompleteField {
1465
1461
  this._openedSubscription.unsubscribe();
1466
1462
  this._subscription.remove(this._openedSubscription);
1467
1463
  }
1468
- const opened$ = this.matAutocomplete._isOpen
1464
+ const opened$ = this.autocomplete._isOpen
1469
1465
  ? timer(0)
1470
- : this.matAutocomplete.opened.pipe(debounceTime(200));
1466
+ : this.autocomplete.opened.pipe(debounceTime(200));
1471
1467
  const scrollEnd$ = opened$
1472
1468
  .pipe(map((_) => this.getAutocompletePanel()), filter(isNotNil), switchMap((panel) => fromScrollEndEvent(panel, threshold)
1473
- .pipe(takeUntil(this.matAutocomplete.closed))));
1469
+ .pipe(takeUntil(this.autocomplete.closed))));
1474
1470
  // Trigger fetch more, end end scroll reached
1475
1471
  this._openedSubscription = scrollEnd$
1476
1472
  .subscribe(() => this._fetchMore$.emit());
@@ -1501,14 +1497,14 @@ class MatAutocompleteField {
1501
1497
  }
1502
1498
  get isOpen() {
1503
1499
  var _a, _b;
1504
- return (this.searchable && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1500
+ return (this.searchable && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1505
1501
  || ((_b = this.matSelect) === null || _b === void 0 ? void 0 : _b.panelOpen)
1506
1502
  || false;
1507
1503
  }
1508
1504
  closePanel() {
1509
1505
  var _a, _b, _c, _d;
1510
- if ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
1511
- (_b = this.matAutocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
1506
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
1507
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
1512
1508
  return;
1513
1509
  }
1514
1510
  if ((_c = this.matSelect) === null || _c === void 0 ? void 0 : _c.panelOpen) {
@@ -1575,7 +1571,7 @@ class MatAutocompleteField {
1575
1571
  }
1576
1572
  getAutocompletePanel() {
1577
1573
  var _a, _b;
1578
- const ele = (_b = (_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
1574
+ const ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
1579
1575
  if (!ele) {
1580
1576
  // DEBUG
1581
1577
  console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
@@ -1609,8 +1605,12 @@ MatAutocompleteField.decorators = [
1609
1605
  { type: Component, args: [{
1610
1606
  // eslint-disable-next-line @angular-eslint/component-selector
1611
1607
  selector: 'mat-autocomplete-field',
1612
- template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- readonly -->\n <ng-container>\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n </ng-container>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"onKeydownEscape.emit($event)\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\"\n [compareWith]=\"compareWith\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"onClick.emit($event)\"\n (focus)=\"filterInputTextFocusInEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"onKeydownEscape.emit($event)\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.opened && onDropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [class.cdk-visually-hidden]=\"!searchable\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count \" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"onDropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1613
- providers: [DEFAULT_VALUE_ACCESSOR$6],
1608
+ template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- readonly -->\n <ng-container>\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n </ng-container>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.opened && dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [class.cdk-visually-hidden]=\"!searchable\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1609
+ providers: [{
1610
+ provide: NG_VALUE_ACCESSOR,
1611
+ multi: true,
1612
+ useExisting: forwardRef(() => MatAutocompleteField)
1613
+ }],
1614
1614
  changeDetection: ChangeDetectionStrategy.OnPush,
1615
1615
  styles: [":host{display:inline-block;position:relative}:host.ion-text-wrap ion-label{white-space:normal!important}button[hidden]{display:none}mat-icon.select-arrow{color:rgba(0,0,0,.47);font-size:150%}.fact-scroll-viewport{height:100%;width:100%}.fact-item{height:54px;display:flex}.fact-item .fact-date{min-width:100px;text-align:center;font-size:24pt}.fact-item .fact-date,.fact-item .fact-text{height:100%;align-items:center;justify-content:center;display:flex}.fact-item .fact-text{border-radius:10px}cdk-virtual-scroll-viewport{border:1px solid #000}cdk-virtual-scroll-viewport li{list-style:none}"]
1616
1616
  },] }
@@ -1620,7 +1620,7 @@ MatAutocompleteField.ctorParameters = () => [
1620
1620
  { type: FormGroupDirective, decorators: [{ type: Optional }] }
1621
1621
  ];
1622
1622
  MatAutocompleteField.propDecorators = {
1623
- compareWith: [{ type: Input }],
1623
+ equals: [{ type: Input }],
1624
1624
  logPrefix: [{ type: Input }],
1625
1625
  formControl: [{ type: Input }],
1626
1626
  formControlName: [{ type: Input }],
@@ -1650,21 +1650,21 @@ MatAutocompleteField.propDecorators = {
1650
1650
  fetchMoreThreshold: [{ type: Input }],
1651
1651
  suggestLengthThreshold: [{ type: Input }],
1652
1652
  showLoadingSpinner: [{ type: Input }],
1653
+ clicked: [{ type: Output, args: ['click',] }],
1654
+ blurred: [{ type: Output, args: ['blur',] }],
1655
+ focused: [{ type: Output, args: ['focus',] }],
1656
+ dropButtonClick: [{ type: Output }],
1657
+ keydownEscape: [{ type: Output, args: ['keydown.escape',] }],
1658
+ keyupEnter: [{ type: Output, args: ['keyup.enter',] }],
1659
+ matSelect: [{ type: ViewChild, args: ['matSelect',] }],
1660
+ matInputText: [{ type: ViewChild, args: ['matInputText',] }],
1661
+ autocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
1662
+ autocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }],
1653
1663
  animationsDisabled: [{ type: HostBinding, args: ['@.disabled',] }],
1654
1664
  filter: [{ type: Input }],
1655
1665
  readonly: [{ type: Input }],
1656
1666
  tabindex: [{ type: Input }],
1657
- items: [{ type: Input }],
1658
- onClick: [{ type: Output, args: ['click',] }],
1659
- onBlur: [{ type: Output, args: ['blur',] }],
1660
- onFocus: [{ type: Output, args: ['focus',] }],
1661
- onDropButtonClick: [{ type: Output, args: ['dropButtonClick',] }],
1662
- onKeydownEscape: [{ type: Output, args: ['keydown.escape',] }],
1663
- onKeyupEnter: [{ type: Output, args: ['keyup.enter',] }],
1664
- matSelect: [{ type: ViewChild, args: ['matSelect',] }],
1665
- matInputText: [{ type: ViewChild, args: ['matInputText',] }],
1666
- matAutocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
1667
- matAutocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }]
1667
+ items: [{ type: Input }]
1668
1668
  };
1669
1669
 
1670
1670
  class DateFormatPipe {
@@ -6545,7 +6545,7 @@ class MatSwipeField {
6545
6545
  // Default values
6546
6546
  this.displayAttributes = this.displayAttributes || ['label', 'name'];
6547
6547
  this.displayWith = this.displayWith || ((obj) => obj && joinPropertiesPath(obj, this.displayAttributes));
6548
- this.compareWithFn = this.compareWithFn || ((o1, o2) => o1 && o2 && o1.id === o2.id);
6548
+ this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
6549
6549
  this.mobile = toBoolean(this.mobile, false);
6550
6550
  }
6551
6551
  ngOnDestroy() {
@@ -6605,7 +6605,7 @@ class MatSwipeField {
6605
6605
  if (this._writing)
6606
6606
  return;
6607
6607
  this._writing = true;
6608
- if (!this.compareWithFn(value, this._value)) {
6608
+ if (!this.equals(value, this._value)) {
6609
6609
  this._value = value;
6610
6610
  this.showSlides = isNotNil(this._value);
6611
6611
  this.updateSlides();
@@ -6689,7 +6689,7 @@ class MatSwipeField {
6689
6689
  }
6690
6690
  updateSlides() {
6691
6691
  if (this.showSlides) {
6692
- const itemIndex = (this.$items.getValue() || []).findIndex(value => this.compareWithFn(value, this._value));
6692
+ const itemIndex = (this.$items.getValue() || []).findIndex(value => this.equals(value, this._value));
6693
6693
  if (itemIndex >= 0) {
6694
6694
  this.slideTo(itemIndex);
6695
6695
  }
@@ -6753,7 +6753,7 @@ MatSwipeField.propDecorators = {
6753
6753
  required: [{ type: Input }],
6754
6754
  mobile: [{ type: Input }],
6755
6755
  clearable: [{ type: Input }],
6756
- compareWithFn: [{ type: Input }],
6756
+ equals: [{ type: Input }],
6757
6757
  displayWith: [{ type: Input }],
6758
6758
  displayAttributes: [{ type: Input }],
6759
6759
  appAutofocus: [{ type: Input }],
@@ -6802,33 +6802,43 @@ class MatChipsField {
6802
6802
  this.required = false;
6803
6803
  this.readonly = false;
6804
6804
  this.clearable = false;
6805
- this.debounceTime = 250;
6806
- this.highlightAccent = false;
6805
+ this.debounceTime = null;
6807
6806
  this.i18nPrefix = 'REFERENTIAL.';
6808
6807
  this.noResultMessage = 'COMMON.NO_RESULT';
6809
6808
  this.debug = false;
6809
+ this.itemSize = '48px';
6810
+ this.fetchMoreThreshold = '15%';
6811
+ this.suggestLengthThreshold = null;
6812
+ this.showLoadingSpinner = true;
6810
6813
  this.clicked = new EventEmitter();
6811
6814
  this.blurred = new EventEmitter();
6812
6815
  this.focused = new EventEmitter();
6816
+ this.dropButtonClick = new EventEmitter(true);
6817
+ this.keydownEscape = new EventEmitter();
6818
+ this.keyupEnter = new EventEmitter();
6813
6819
  this.$inputItems = new BehaviorSubject(undefined);
6814
- this.onDropButtonClick = new EventEmitter(true);
6820
+ this.$filteredItems = new BehaviorSubject(undefined);
6815
6821
  this.inputControl = new FormControl();
6816
- this.getPropertyByPath = getPropertyByPath;
6822
+ this._fetchMore$ = new EventEmitter();
6817
6823
  this._subscription = new Subscription();
6818
6824
  this._$filter = new BehaviorSubject(undefined);
6825
+ this._reload$ = new Subject();
6819
6826
  }
6820
6827
  get itemCount() {
6821
6828
  return this._itemCount;
6822
6829
  }
6830
+ get canFetchMore() {
6831
+ return this._onFetchMoreCallback && this._moreItemsCount > 0;
6832
+ }
6823
6833
  set filter(value) {
6824
- if (this.debug)
6825
- console.debug(this.logPrefix + ' Setting filter:', value);
6826
- if (value !== this._$filter.getValue()) {
6834
+ if (value !== this._$filter.value) {
6835
+ // DEBUG
6836
+ //console.debug(this.logPrefix + " Setting filter:", value);
6827
6837
  this._$filter.next(value);
6828
6838
  }
6829
6839
  }
6830
6840
  get filter() {
6831
- return this._$filter.getValue();
6841
+ return this._$filter.value;
6832
6842
  }
6833
6843
  set tabindex(value) {
6834
6844
  this._tabindex = value;
@@ -6840,19 +6850,25 @@ class MatChipsField {
6840
6850
  set items(value) {
6841
6851
  // Remove previous subscription on items, (if exits)
6842
6852
  if (this._itemsSubscription) {
6843
- console.warn('Items received twice !');
6853
+ console.warn(this.logPrefix + ' Items received twice !');
6844
6854
  this._subscription.remove(this._itemsSubscription);
6845
6855
  this._itemsSubscription.unsubscribe();
6846
6856
  }
6847
6857
  if (isObservable(value)) {
6848
- this._itemsSubscription = this._subscription.add(value.subscribe(v => this.$inputItems.next(v)));
6858
+ this._itemsSubscription = this._subscription.add(value.subscribe(v => {
6859
+ //console.warn(this.logPrefix + " Received items: ", v);
6860
+ this.$inputItems.next(v);
6861
+ }));
6849
6862
  }
6850
6863
  else {
6851
- if (value !== this.$inputItems.getValue()) {
6864
+ if (value !== this.$inputItems.value) {
6852
6865
  this.$inputItems.next(value);
6853
6866
  }
6854
6867
  }
6855
6868
  }
6869
+ get items() {
6870
+ return this.$inputItems;
6871
+ }
6856
6872
  get value() {
6857
6873
  return this.formControl.value || [];
6858
6874
  }
@@ -6863,6 +6879,7 @@ class MatChipsField {
6863
6879
  return !this.readonly && this.formControl.enabled;
6864
6880
  }
6865
6881
  ngOnInit() {
6882
+ var _a, _b;
6866
6883
  this.formControl = this.formControl || this.formControlName && this.formGroupDir && this.formGroupDir.form.get(this.formControlName);
6867
6884
  if (!this.formControl)
6868
6885
  throw new Error('Missing mandatory attribute \'formControl\' or \'formControlName\' in <mat-chips-field>.');
@@ -6877,85 +6894,201 @@ class MatChipsField {
6877
6894
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
6878
6895
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
6879
6896
  this.displayWith = this.displayWith || this.config.displayWith;
6880
- this.compareWith = this.compareWith || this.config.compareWith;
6897
+ this.equals = this.equals || this.config.equals;
6881
6898
  this.mobile = toBoolean(this.mobile, this.config.mobile);
6882
- this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, true));
6899
+ this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
6900
+ this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
6883
6901
  this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus, true));
6884
- this.class = this.class || this.config.class;
6902
+ this.classList = this.classList || this.config.class;
6903
+ this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
6904
+ this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
6885
6905
  }
6886
6906
  // Default values
6887
- this.displayAttributes = this.displayAttributes || (this.filter && this.filter.attributes) || ['label', 'name'];
6907
+ this.displayAttributes = this.displayAttributes || ((_a = this.filter) === null || _a === void 0 ? void 0 : _a.attributes) || ['label', 'name'];
6888
6908
  this.displayWith = this.displayWith || ((obj) => obj && joinPropertiesPath(obj, this.displayAttributes));
6889
- this.compareWith = this.compareWith || ((o1, o2) => o1 && o2 && o1.id === o2.id);
6890
- this.displayColumnSizes = this.displayColumnSizes || this.displayAttributes.map(attr => (
6891
- // If label then col size = 2
6892
- attr && attr.endsWith('label')) ? 2 :
6893
- // If rankOrder then col size = 1
6894
- (attr && attr.endsWith('rankOrder') ? 1 :
6895
- // Else, auto size
6896
- undefined));
6909
+ this.displayColumnSizes = this.displayColumnSizes
6910
+ // if only column: auto size
6911
+ || (this.displayAttributes.length === 1 && [undefined])
6912
+ // Computed column size:
6913
+ // - if label then col size = 2
6914
+ // - if rankOrder then col size = 1
6915
+ // - ese => auto size
6916
+ || this.displayAttributes.map(attr => (attr && attr.endsWith('label')) ? 2
6917
+ : ((attr && attr.endsWith('rankOrder')) ? 1
6918
+ : undefined));
6897
6919
  this.displayColumnNames = this.displayAttributes.map((attr, index) => this.displayColumnNames && this.displayColumnNames[index] ||
6898
6920
  (this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()));
6899
6921
  this.mobile = toBoolean(this.mobile, false);
6922
+ this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
6923
+ const classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
6924
+ this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
6925
+ || (classList.includes('min-width-large') && '400px')
6926
+ || (classList.includes('min-width-xlarge') && '450px')
6927
+ || (classList.includes('mat-autocomplete-panel-full-size') && '100vw')));
6928
+ this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, true);
6929
+ this.debounceTime = toNumber(this.debounceTime, 250);
6930
+ this.highlightAccent = toBoolean(this.highlightAccent, false);
6931
+ this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
6932
+ this.matAutocompletePosition = this.matAutocompletePosition || (this.mobile ? 'above' : 'auto'); // On mobile, set position to above (because of bottom keyboard)
6900
6933
  // No suggestFn: filter on the given items
6901
6934
  if (!this.suggestFn) {
6902
6935
  const suggestFromArrayFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
6903
6936
  if (this.debug)
6904
6937
  console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
6905
- const { data, total } = yield suggestFromArray(this.$inputItems.getValue(), value, Object.assign({ searchAttributes: this.displayAttributes }, filter));
6906
- this._itemCount = toNumber(total, data && data.length || 0);
6907
- return { data, total };
6938
+ return suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter));
6908
6939
  });
6909
6940
  // Wait (once) that items are loaded, then call suggest from array fn
6910
6941
  this.suggestFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
6911
- if (isNil(this.$inputItems.getValue())) {
6942
+ if (isNil(this.$inputItems.value)) {
6912
6943
  if (this.debug)
6913
6944
  console.debug('[mat-chips] Waiting items to be set...');
6914
6945
  yield firstNotNilPromise(this.$inputItems);
6915
6946
  if (this.debug)
6916
- console.debug('[mat-chips] Received items:', this.$inputItems.getValue());
6947
+ console.debug('[mat-chips] Received items:', this.$inputItems.value);
6917
6948
  }
6918
6949
  this.suggestFn = suggestFromArrayFn;
6919
- return this.suggest(value, filter); // Loop
6950
+ return this.suggestFn(value, filter); // Loop
6920
6951
  });
6921
6952
  }
6922
- // this.matSelectItems$ = this.$inputItems
6923
- // .pipe(
6924
- // filter(isNotNil),
6925
- // map((items) => {
6926
- // // Make sure control value is inside
6927
- // const value = this.inputControl.value;
6928
- // // If form value is missing: add it to the list
6929
- // if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.compareWith(item, value)) === -1) {
6930
- // // console.debug(this.logPrefix + " Add form value to items, because missed in items", value);
6931
- // return items.concat(value);
6932
- // }
6933
- // return items;
6934
- // })
6935
- // );
6936
- this._subscription.add(this.onDropButtonClick
6937
- .pipe(filter(event => (!event || !event.defaultPrevented) && this.formControl.enabled))
6938
- .subscribe(() => {
6939
- this.matInputText.nativeElement.focus();
6940
- }));
6941
- const updateFilteredItemsEvents$ = merge(
6953
+ const filteredItemsChanges = merge(
6954
+ // Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
6955
+ this._reload$, this.inputControl.valueChanges
6956
+ .pipe(filter(value => this.enabled && isNotNilString(value)),
6957
+ // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
6958
+ tap(_ => this.showLoadingSpinner && this.markAsLoading()),
6959
+ // Filter if not enough character
6960
+ filter(value => value.length >= this.suggestLengthThreshold),
6961
+ // Wait a debounce time
6962
+ debounceTime(this.debounceTime)
6963
+ // DEBUG
6964
+ //tap((value) => console.debug(this.logPrefix + ' Search text changes:', value))
6965
+ ),
6966
+ // Object set: use it (no distinctUntilChanged() pipe need)
6967
+ this.inputControl.valueChanges
6968
+ .pipe(startWith(this.inputControl.value), filter(value => isNotNil(value) && typeof value === 'object'), tap(value => {
6969
+ // DEBUG
6970
+ //console.debug(this.logPrefix + ' object changes:', value)
6971
+ // Update the display value (if need)
6972
+ const displayValue = this.displayWith(value) || '';
6973
+ // Apply to the input[type=text] field
6974
+ if (this.matInputText && this.matInputText.nativeElement) {
6975
+ this.matInputText.nativeElement.value = displayValue;
6976
+ }
6977
+ })
6978
+ // DEBUG
6979
+ //tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
6980
+ ),
6981
+ // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
6982
+ merge(
6942
6983
  // Focus or click => Load all
6943
6984
  merge(this.focused, this.clicked)
6944
- .pipe(filter(_ => this.enabled), map((_) => this.showAllOnFocus ? '*' : this.inputControl.value)), this.inputControl.valueChanges
6945
- .pipe(startWith(this.inputControl.value), filter(value => (isNotNil(value) && typeof value === 'object') || (isNotNilString(value) && !value.includes('**'))), tap((value) => {
6946
- if (this.debug)
6947
- console.debug(this.logPrefix + ' valueChanges:', value);
6948
- }), debounceTime(this.debounceTime)), this.$inputItems
6949
- .pipe(map(() => this.formControl.value)), this._$filter
6950
- .pipe(map(() => this.formControl.value)));
6951
- this.filteredItems$ = updateFilteredItemsEvents$
6952
- .pipe(distinctUntilChanged(),
6953
- //tap(value => this.debug && console.debug(this.logPrefix + " Received update event: ", value)),
6954
- switchMap((value) => this.suggest(value, this.filter)));
6985
+ .pipe(filter(_ => this.enabled), map((_) => this.showAllOnFocus ? '*' : this.inputControl.value)),
6986
+ // On dropdown button click
6987
+ this.dropButtonClick
6988
+ .pipe(filter(event => this.enabled && (!event || !event.defaultPrevented)), map(_ => this.showAllOnFocus ? '*' : this.inputControl.value)), merge(this.$inputItems, this._$filter)
6989
+ .pipe(filter(_ => this.enabled), map(_ => this.inputControl.value)))
6990
+ .pipe(
6991
+ // Start to suggest when :
6992
+ // - '*'
6993
+ // - is nil, and there is no min length threshold
6994
+ // - is not nil and not a string type (e.g. object)
6995
+ // - is not nil and is a string, and has enough character
6996
+ filter(value => value === '*'
6997
+ || (isNil(value)
6998
+ ? (this.suggestLengthThreshold <= 0)
6999
+ : (!(typeof value === 'string')
7000
+ || value.length >= this.suggestLengthThreshold))),
7001
+ // Distinguish changes
7002
+ distinctUntilChanged()))
7003
+ .pipe(
7004
+ // Suggest values
7005
+ mergeMap(value => this.suggest(value, this.filter)),
7006
+ // DEBUG
7007
+ //tap(items => console.debug(this.logPrefix + ' Received from suggest: ', items)),
7008
+ // Store implicit value (will use it onBlur if not other value selected)
7009
+ tap(items => this.updateImplicitValue(items)));
7010
+ // Fetch more events
7011
+ const fetchMoreItemsChanges = this._fetchMore$
7012
+ .pipe(tap(event => event === null || event === void 0 ? void 0 : event.preventDefault()), // Avoid to close the mat-select
7013
+ filter(() => this.canFetchMore), mergeMap(() => this.fetchMore()),
7014
+ // DEBUG
7015
+ //tap(moreItems => console.debug(this.logPrefix + ' Received from fetch More: ', moreItems)),
7016
+ // Concat to existing items
7017
+ map(moreItems => (this.$filteredItems.value || []).concat(moreItems)));
7018
+ // Update filtered items
7019
+ this._subscription.add(merge(this.$inputItems,
7020
+ // Update items events
7021
+ filteredItemsChanges,
7022
+ // Fetch more events
7023
+ fetchMoreItemsChanges)
7024
+ // Emit items
7025
+ .subscribe(items => this.$filteredItems.next(items)));
7026
+ // Applying implicit value, on blur
7027
+ this._subscription.add(this.blurred
7028
+ .pipe(map(_ => this.formControl.value))
7029
+ .subscribe(value => {
7030
+ // When leave component without object, use implicit value if :
7031
+ // - an explicit value
7032
+ // - field is not empty (user fill something)
7033
+ // - OR field empty but is required
7034
+ if (this._implicitValue && ((this.required && isNilOrBlank(value)) || (isNotNilOrBlank(value) && typeof value !== 'object'))) {
7035
+ this.writeValue(this._implicitValue);
7036
+ this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7037
+ this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7038
+ this.checkIfTouched();
7039
+ }
7040
+ else if (isNilOrBlank(value)) {
7041
+ this.writeValue(null);
7042
+ this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7043
+ this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7044
+ this.checkIfTouched();
7045
+ }
7046
+ this._implicitValue = null; // reset the implicit value
7047
+ }));
7048
+ this._subscription.add(this.keydownEscape.subscribe(event => {
7049
+ if (this.isOpen) {
7050
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
7051
+ event === null || event === void 0 ? void 0 : event.preventDefault();
7052
+ // DEBUG
7053
+ //console.debug(this.logPrefix + " Closing the panel (keydown.escape)");
7054
+ this.closePanel();
7055
+ }
7056
+ }));
6955
7057
  }
6956
7058
  ngOnDestroy() {
6957
7059
  this._subscription.unsubscribe();
7060
+ if (this._itemsSubscription) {
7061
+ this._itemsSubscription.unsubscribe();
7062
+ }
7063
+ if (this._openedSubscription) {
7064
+ this._openedSubscription.unsubscribe();
7065
+ }
6958
7066
  this.$inputItems.complete();
7067
+ this.$filteredItems.complete();
7068
+ this._reload$.complete();
7069
+ this._$filter.complete();
7070
+ this.dropButtonClick.complete();
7071
+ this.clicked.complete();
7072
+ this.blurred.complete();
7073
+ this.focused.complete();
7074
+ this.keydownEscape.complete();
7075
+ this.keyupEnter.complete();
7076
+ this._fetchMore$.complete();
7077
+ this._implicitValue = undefined;
7078
+ this.formControl = null;
7079
+ this.displayWith = null;
7080
+ this.equals = null;
7081
+ this.suggestFn = null;
7082
+ this.$filteredItems = null;
7083
+ this.config = null;
7084
+ this.classList = null;
7085
+ this._onChangeCallback = null;
7086
+ this._onTouchedCallback = null;
7087
+ this._onFetchMoreCallback = null;
7088
+ // Destroy the 'autocomplete' instance, to avoid memory leak
7089
+ if (this.autocomplete) {
7090
+ this.autocomplete.ngOnDestroy();
7091
+ }
6959
7092
  }
6960
7093
  /**
6961
7094
  * Add item to chips
@@ -6976,19 +7109,21 @@ class MatChipsField {
6976
7109
  * @param item
6977
7110
  */
6978
7111
  remove(item) {
6979
- const index = this.value && this.value.indexOf(item);
6980
- if (index >= 0) {
6981
- const value = this.value.slice();
6982
- value.splice(index, 1);
6983
- this.writeValue(value);
6984
- this.inputControl.setValue('');
7112
+ const value = this.value;
7113
+ const index = value ? value.indexOf(item) : -1;
7114
+ if (index !== -1) {
7115
+ const newValue = value.slice();
7116
+ newValue.splice(index, 1);
7117
+ this.writeValue(newValue);
7118
+ this.closePanel();
6985
7119
  }
6986
7120
  }
6987
7121
  /**
6988
7122
  * Allow to reload content. Useful when filter has been changed but not detected
6989
7123
  */
6990
- reloadItems() {
6991
- this.onDropButtonClick.emit();
7124
+ reloadItems(value) {
7125
+ // Force a refresh
7126
+ this._reload$.next(value || '*');
6992
7127
  }
6993
7128
  writeValue(value) {
6994
7129
  if (this.debug)
@@ -7005,6 +7140,10 @@ class MatChipsField {
7005
7140
  this._onTouchedCallback = fn;
7006
7141
  }
7007
7142
  setDisabledState(isDisabled) {
7143
+ var _a;
7144
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
7145
+ this.closePanel();
7146
+ }
7008
7147
  this.cd.markForCheck();
7009
7148
  }
7010
7149
  focus() {
@@ -7024,6 +7163,7 @@ class MatChipsField {
7024
7163
  return false;
7025
7164
  }
7026
7165
  const hasContent = selectInputContent(event);
7166
+ // If combo is empty, or if has content but should force to show panel on focus
7027
7167
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
7028
7168
  if (this.debug)
7029
7169
  console.debug(this.logPrefix + ' Emit focus event');
@@ -7032,10 +7172,67 @@ class MatChipsField {
7032
7172
  }
7033
7173
  return false;
7034
7174
  }
7175
+ filterInputTextBlurEvent(event) {
7176
+ if (!event || event.defaultPrevented)
7177
+ return;
7178
+ // Ignore event from mat-option
7179
+ if (event.relatedTarget instanceof HTMLElement && event.relatedTarget.tagName === 'MAT-OPTION') {
7180
+ event.preventDefault();
7181
+ if (event.stopPropagation)
7182
+ event.stopPropagation();
7183
+ event.returnValue = false;
7184
+ //DEBUG console.debug(this.logPrefix + " Cancelling blur event");
7185
+ return false;
7186
+ }
7187
+ //DEBUG
7188
+ //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
7189
+ // Move caret to the beginning (fix issue IMAGINE-469)
7190
+ selectInputRange(event.target, 0, 0);
7191
+ this.blurred.emit(event);
7192
+ return true;
7193
+ }
7194
+ filterChipsFocusEvent(event) {
7195
+ // DEBUG
7196
+ if (this.debug)
7197
+ console.debug(this.logPrefix + ' Focus in chips list', event);
7198
+ this.matInputText.nativeElement.focus();
7199
+ }
7035
7200
  clearValue(event) {
7036
7201
  this.writeValue(null);
7037
7202
  event.stopPropagation();
7038
7203
  }
7204
+ _initAutocompleteInfiniteScroll(threshold) {
7205
+ if (!this.autocomplete)
7206
+ return; // Skip
7207
+ // DEBUG
7208
+ //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
7209
+ if (this._openedSubscription) {
7210
+ this._openedSubscription.unsubscribe();
7211
+ this._subscription.remove(this._openedSubscription);
7212
+ }
7213
+ const opened$ = this.autocomplete._isOpen
7214
+ ? timer(0)
7215
+ : this.autocomplete.opened.pipe(debounceTime(200));
7216
+ const scrollEnd$ = opened$
7217
+ .pipe(map((_) => this.getAutocompletePanel()), filter(isNotNil), switchMap((panel) => fromScrollEndEvent(panel, threshold)
7218
+ .pipe(takeUntil(this.autocomplete.closed))));
7219
+ // Trigger fetch more, end end scroll reached
7220
+ this._openedSubscription = scrollEnd$
7221
+ .subscribe(() => this._fetchMore$.emit());
7222
+ // Register subscription
7223
+ this._subscription.add(this._openedSubscription);
7224
+ }
7225
+ get isOpen() {
7226
+ var _a;
7227
+ return ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) || false;
7228
+ }
7229
+ closePanel() {
7230
+ var _a, _b;
7231
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
7232
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
7233
+ return;
7234
+ }
7235
+ }
7039
7236
  /* -- private method -- */
7040
7237
  suggest(value, filter) {
7041
7238
  return __awaiter(this, void 0, void 0, function* () {
@@ -7057,7 +7254,7 @@ class MatChipsField {
7057
7254
  this._itemCount = toNumber(total, data && data.length || 0);
7058
7255
  }
7059
7256
  // Filter out existing items
7060
- const filteredData = (res || []).slice().filter(item1 => this.value.findIndex(item2 => this.compareWith(item1, item2)) === -1);
7257
+ const filteredData = (res || []).slice().filter(item1 => this.value.findIndex(item2 => this.equals(item1, item2)) === -1);
7061
7258
  // Update items count
7062
7259
  this._itemCount = this._itemCount - (((res === null || res === void 0 ? void 0 : res.length) || 0) - ((filteredData === null || filteredData === void 0 ? void 0 : filteredData.length) || 0));
7063
7260
  if (this.debug)
@@ -7065,15 +7262,64 @@ class MatChipsField {
7065
7262
  return res;
7066
7263
  });
7067
7264
  }
7265
+ fetchMore() {
7266
+ return __awaiter(this, void 0, void 0, function* () {
7267
+ if (!this._onFetchMoreCallback)
7268
+ return [];
7269
+ // Save then remove fetch function (to avoid multi-call)
7270
+ const fetchMoreFn = this._onFetchMoreCallback;
7271
+ this._onFetchMoreCallback = undefined;
7272
+ const { data, total, fetchMore } = yield fetchMoreFn();
7273
+ this._itemCount = total || this._itemCount;
7274
+ this._onFetchMoreCallback = fetchMore;
7275
+ this._moreItemsCount = Math.max(0, this._moreItemsCount - data.length); // Borne min = 0
7276
+ return data;
7277
+ });
7278
+ }
7279
+ updateImplicitValue(items) {
7280
+ // Store implicit value (will use it onBlur if not other value selected)
7281
+ if (items && items.length === 1) {
7282
+ this._implicitValue = items[0];
7283
+ //this.formControl.setErrors(null);
7284
+ }
7285
+ else {
7286
+ this._implicitValue = undefined;
7287
+ }
7288
+ }
7289
+ getAutocompletePanel() {
7290
+ var _a, _b;
7291
+ const ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
7292
+ if (!ele) {
7293
+ // DEBUG
7294
+ console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
7295
+ }
7296
+ return ele;
7297
+ }
7298
+ checkIfTouched() {
7299
+ if (this.formControl.touched) {
7300
+ this.cd.markForCheck();
7301
+ this._onTouchedCallback();
7302
+ }
7303
+ }
7068
7304
  markForCheck() {
7069
7305
  this.cd.markForCheck();
7070
7306
  }
7307
+ markAsLoading() {
7308
+ if (this.$filteredItems.value) {
7309
+ this.$filteredItems.next(undefined);
7310
+ this._itemCount = undefined;
7311
+ this._implicitValue = undefined;
7312
+ this._onFetchMoreCallback = undefined;
7313
+ this._moreItemsCount = 0;
7314
+ this.markForCheck();
7315
+ }
7316
+ }
7071
7317
  }
7072
7318
  MatChipsField.decorators = [
7073
7319
  { type: Component, args: [{
7074
7320
  // eslint-disable-next-line @angular-eslint/component-selector
7075
7321
  selector: 'mat-chips-field',
7076
- template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\" class=\"material-chips\" [class.mat-form-field-disabled]=\"disabled\">\n <div matPrefix>\n <ng-content select=\"[matPrefix]\"></ng-content>\n </div>\n <mat-label>{{placeholder}}</mat-label>\n <mat-chip-list #chipList>\n <mat-chip\n *ngFor=\"let item of value\"\n [selectable]=\"false\"\n [removable]=\"!disabled\"\n (removed)=\"remove(item)\">\n {{displayWith(item)}}\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\n </mat-chip>\n\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autoCombo\"\n [formControl]=\"inputControl\"\n [appAutofocus]=\"appAutofocus\"\n [tabindex]=\"_tabindex\"\n [readonly]=\"disabled\"\n [hidden]=\"disabled\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (blur)=\"blurred.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (keyup.arrowdown)=\"!autoCombo.showPanel && onDropButtonClick.emit($event)\"\n [matChipInputFor]=\"chipList\"\n >\n </mat-chip-list>\n\n <!-- autocomplete -->\n <mat-autocomplete #autoCombo=\"matAutocomplete\"\n (optionSelected)=\"add($event)\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"class\">\n <ng-container *ngIf=\"(filteredItems$ | async) as items\">\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"isLast\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: itemCount} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <!-- No item option -->\n <mat-option *ngIf=\"!items.length\" class=\"ion-no-padding\" [disabled]=\"true\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row>\n <ion-col *ngFor=\"let attr of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"getPropertyByPath(item, attr) | highlight: { search: inputControl.value, withAccent: highlightAccent } \"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n </ng-container>\n </mat-autocomplete>\n\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"onDropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n <ng-content matSuffix select=\"[matSuffix]\"></ng-content>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n\n </mat-form-field>\n\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n",
7322
+ template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\" class=\"material-chips\" [class.mat-form-field-disabled]=\"disabled\">\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n <mat-label>{{placeholder}}</mat-label>\n <mat-chip-list #chipList (focus)=\"matInputText.focus()\">\n <mat-chip\n *ngFor=\"let item of value\"\n [selectable]=\"false\"\n [removable]=\"!disabled\"\n (removed)=\"remove(item)\">\n {{displayWith(item)}}\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\n </mat-chip>\n\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"inputControl\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [readonly]=\"disabled\"\n [hidden]=\"disabled\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\"\n [matChipInputFor]=\"chipList\"\n >\n </mat-chip-list>\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n (optionSelected)=\"add($event)\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: inputControl.value, withAccent: highlightAccent } \"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
7077
7323
  providers: [
7078
7324
  {
7079
7325
  provide: NG_VALUE_ACCESSOR,
@@ -7090,7 +7336,7 @@ MatChipsField.ctorParameters = () => [
7090
7336
  { type: FormGroupDirective, decorators: [{ type: Optional }] }
7091
7337
  ];
7092
7338
  MatChipsField.propDecorators = {
7093
- compareWith: [{ type: Input }],
7339
+ equals: [{ type: Input }],
7094
7340
  logPrefix: [{ type: Input }],
7095
7341
  formControl: [{ type: Input }],
7096
7342
  formControlName: [{ type: Input }],
@@ -7109,16 +7355,26 @@ MatChipsField.propDecorators = {
7109
7355
  highlightAccent: [{ type: Input }],
7110
7356
  showAllOnFocus: [{ type: Input }],
7111
7357
  showPanelOnFocus: [{ type: Input }],
7112
- appAutofocus: [{ type: Input }],
7358
+ autofocus: [{ type: Input }],
7113
7359
  config: [{ type: Input }],
7114
7360
  i18nPrefix: [{ type: Input }],
7115
7361
  noResultMessage: [{ type: Input }],
7116
- class: [{ type: Input }],
7362
+ classList: [{ type: Input, args: ['class',] }],
7363
+ panelWidth: [{ type: Input }],
7364
+ matAutocompletePosition: [{ type: Input }],
7117
7365
  debug: [{ type: Input }],
7366
+ itemSize: [{ type: Input }],
7367
+ fetchMoreThreshold: [{ type: Input }],
7368
+ suggestLengthThreshold: [{ type: Input }],
7369
+ showLoadingSpinner: [{ type: Input }],
7118
7370
  clicked: [{ type: Output }],
7119
7371
  blurred: [{ type: Output }],
7120
7372
  focused: [{ type: Output }],
7373
+ dropButtonClick: [{ type: Output }],
7374
+ keydownEscape: [{ type: Output, args: ['keydown.escape',] }],
7375
+ keyupEnter: [{ type: Output, args: ['keyup.enter',] }],
7121
7376
  matInputText: [{ type: ViewChild, args: ['matInputText',] }],
7377
+ autocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
7122
7378
  autocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }],
7123
7379
  filter: [{ type: Input }],
7124
7380
  tabindex: [{ type: Input }],
@@ -16360,7 +16616,7 @@ class AutocompleteTestPage {
16360
16616
  AutocompleteTestPage.decorators = [
16361
16617
  { type: Component, args: [{
16362
16618
  selector: 'app-autocomplete-test',
16363
- template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable&lt;any[]&gt;</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) =&gt; any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter('entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [compareWith]=\"compareWithFn\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggest]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [compareWith]=\"compareWithFn\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16619
+ template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable&lt;any[]&gt;</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) =&gt; any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter('entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggest]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [equals]=\"compareWithFn\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16364
16620
  },] }
16365
16621
  ];
16366
16622
  AutocompleteTestPage.ctorParameters = () => [
@@ -16515,7 +16771,7 @@ class SwipeTestPage {
16515
16771
  SwipeTestPage.decorators = [
16516
16772
  { type: Component, args: [{
16517
16773
  selector: 'app-swipe-test',
16518
- template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Swipe test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <h1>Swipe page:</h1>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <ion-row>\n <!-- empty -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"empty\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [compareWithFn]=\"compareDate()\"\n [tabindex]=\"1\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- date -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Date\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"date\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [compareWithFn]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"2\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <!-- disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled empty\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"disabledEmpty\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [compareWithFn]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"3\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n<!-- read-only-->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled with date\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"disabledDate\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [compareWithFn]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"4\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16774
+ template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Swipe test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <h1>Swipe page:</h1>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <ion-row>\n <!-- empty -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"empty\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [equals]=\"compareDate()\"\n [tabindex]=\"1\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- date -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Date\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"date\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [equals]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"2\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <!-- disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled empty\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"disabledEmpty\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [equals]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"3\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n<!-- read-only-->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled with date\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-swipe-field formControlName=\"disabledDate\"\n placeholder=\"placeholder\"\n [items]=\"$dates\"\n [displayWith]=\"displayDate()\"\n [equals]=\"compareDate()\"\n [clearable]=\"true\"\n [tabindex]=\"4\"\n [debug]=\"true\"\n >\n </mat-swipe-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16519
16775
  },] }
16520
16776
  ];
16521
16777
  SwipeTestPage.ctorParameters = () => [
@@ -16644,13 +16900,15 @@ class ChipsTestPage {
16644
16900
  this.autocompleteFields.add('entity-suggestFn', {
16645
16901
  suggestFn: (value, filter) => this.suggest(value, filter),
16646
16902
  attributes: ['label', 'name'],
16647
- displayWith: this.entityToString
16903
+ displayWith: this.entityToString,
16904
+ equals: (o1, o2) => EntityUtils.compare(o1, o2, 1, 'id') === 0
16648
16905
  });
16649
16906
  // From items
16650
16907
  this.autocompleteFields.add('entity-items', {
16651
16908
  items: FAKE_ENTITIES.slice(),
16652
16909
  attributes: ['label', 'name'],
16653
- displayWith: this.entityToString
16910
+ displayWith: this.entityToString,
16911
+ equals: (o1, o2) => EntityUtils.compare(o1, o2, 1, 'id') === 0
16654
16912
  });
16655
16913
  // From items
16656
16914
  this.autocompleteFields.add('entity-$items', {
@@ -16702,7 +16960,7 @@ class ChipsTestPage {
16702
16960
  ChipsTestPage.decorators = [
16703
16961
  { type: Component, args: [{
16704
16962
  selector: 'app-chips-test',
16705
- template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Chips field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <ion-row>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Suggest() function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <pre><small>suggestFn: (searchText, filter) =&gt; any[]</small></pre>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [logPrefix]=\"'[mat-chips-empty] '\"\n [compareWith]=\"compareWithFn\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function with initial value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <pre><small>suggestFn: (searchText, filter) =&gt; any[]</small></pre>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entityInitial\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-initialized] '\"\n ></mat-chips-field>\n {{stringify(form.controls.entityInitial.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-disabled] '\"\n ></mat-chips-field>\n {{stringify(form.controls.disableEntity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [compareWith]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-readonly] '\"\n [readonly]=\"true\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16963
+ template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Chips field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <ion-row>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Suggest() function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <pre><small>suggestFn: (searchText, filter) =&gt; any[]</small></pre>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [logPrefix]=\"'[mat-chips-empty] '\"\n [equals]=\"compareWithFn\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function with initial value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <pre><small>suggestFn: (searchText, filter) =&gt; any[]</small></pre>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entityInitial\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-initialized] '\"\n ></mat-chips-field>\n {{stringify(form.controls.entityInitial.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-disabled] '\"\n ></mat-chips-field>\n {{stringify(form.controls.disableEntity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[mat-chips-readonly] '\"\n [readonly]=\"true\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
16706
16964
  },] }
16707
16965
  ];
16708
16966
  ChipsTestPage.ctorParameters = () => [
@@ -16966,6 +17224,9 @@ class AppForm {
16966
17224
  this.onSubmit.complete();
16967
17225
  this.onSubmit.unsubscribe();
16968
17226
  this._$ready.complete();
17227
+ this._$ready.unsubscribe();
17228
+ this._$loading.complete();
17229
+ this._$loading.unsubscribe();
16969
17230
  }
16970
17231
  cancel() {
16971
17232
  this.onCancel.emit();
@@ -17070,9 +17331,7 @@ class AppForm {
17070
17331
  * @param opts
17071
17332
  */
17072
17333
  ready(opts) {
17073
- return __awaiter(this, void 0, void 0, function* () {
17074
- yield firstTruePromise(this._$ready);
17075
- });
17334
+ return waitForTrue(this._$ready, opts);
17076
17335
  }
17077
17336
  /**
17078
17337
  * Wait form is idle (not loading)
@@ -17245,11 +17504,18 @@ AuthForm.propDecorators = {
17245
17504
  };
17246
17505
 
17247
17506
  class AuthModal {
17248
- constructor(accountService, viewCtrl, changeDetectorRef) {
17507
+ constructor(accountService, viewCtrl, cd) {
17249
17508
  this.accountService = accountService;
17250
17509
  this.viewCtrl = viewCtrl;
17251
- this.changeDetectorRef = changeDetectorRef;
17252
- this.loading = false;
17510
+ this.cd = cd;
17511
+ }
17512
+ get loading() {
17513
+ var _a;
17514
+ return (_a = this.form) === null || _a === void 0 ? void 0 : _a.loading;
17515
+ }
17516
+ ngOnInit() {
17517
+ this.form.markAsReady({ emitEvent: false });
17518
+ this.form.markAsLoaded();
17253
17519
  }
17254
17520
  cancel() {
17255
17521
  this.viewCtrl.dismiss();
@@ -17259,10 +17525,10 @@ class AuthModal {
17259
17525
  if (this.form.disabled)
17260
17526
  return;
17261
17527
  if (!this.form.valid) {
17262
- this.form.markAsTouched();
17528
+ this.form.markAllAsTouched();
17263
17529
  return;
17264
17530
  }
17265
- this.loading = true;
17531
+ this.markAsLoading();
17266
17532
  try {
17267
17533
  const data = this.form.value;
17268
17534
  // Disable the form
@@ -17271,9 +17537,8 @@ class AuthModal {
17271
17537
  return this.viewCtrl.dismiss(account);
17272
17538
  }
17273
17539
  catch (err) {
17274
- this.loading = false;
17275
17540
  this.form.error = err && err.message || err;
17276
- this.markForCheck();
17541
+ this.markAsLoaded();
17277
17542
  // Enable the form
17278
17543
  this.form.enable();
17279
17544
  // Reset form error on next changes
@@ -17286,7 +17551,13 @@ class AuthModal {
17286
17551
  });
17287
17552
  }
17288
17553
  markForCheck() {
17289
- this.changeDetectorRef.markForCheck();
17554
+ this.cd.markForCheck();
17555
+ }
17556
+ markAsLoading(opts) {
17557
+ this.form.markAsLoading(opts);
17558
+ }
17559
+ markAsLoaded(opts) {
17560
+ this.form.markAsLoaded(opts);
17290
17561
  }
17291
17562
  }
17292
17563
  AuthModal.decorators = [
@@ -20470,6 +20741,7 @@ class EntitiesTableDataSource extends TableDataSource {
20470
20741
  this._useValidator = false;
20471
20742
  this._stopWatching$ = new Subject();
20472
20743
  this._editingRowCount = 0;
20744
+ this._fetchMoreFn = null;
20473
20745
  this.loadingSubject = new BehaviorSubject(undefined);
20474
20746
  this._options = Object.assign({ dataServiceOptions: {}, debug: config && config.suppressErrors === false, keepOriginalDataAfterConfirm: false }, config);
20475
20747
  this._useValidator = isNotNil(validatorService);
@@ -20502,6 +20774,7 @@ class EntitiesTableDataSource extends TableDataSource {
20502
20774
  watchAll(offset, size, sortBy, sortDirection, filter) {
20503
20775
  this._stopWatching$.next();
20504
20776
  this._editingRowCount = 0;
20777
+ this._fetchMoreFn = null;
20505
20778
  this.markAsLoading();
20506
20779
  return this.dataService.watchAll(offset, size, sortBy, sortDirection, filter, this.serviceOptions)
20507
20780
  .pipe(
@@ -20515,6 +20788,7 @@ class EntitiesTableDataSource extends TableDataSource {
20515
20788
  }
20516
20789
  else {
20517
20790
  this.updateDatasource((res.data || []));
20791
+ this._fetchMoreFn = res.fetchMore;
20518
20792
  }
20519
20793
  return res;
20520
20794
  }));
@@ -20743,6 +21017,37 @@ class EntitiesTableDataSource extends TableDataSource {
20743
21017
  this._creating = false;
20744
21018
  });
20745
21019
  }
21020
+ getData() {
21021
+ return __awaiter(this, void 0, void 0, function* () {
21022
+ const rows = yield this.getRows();
21023
+ return this.getDataFromRows(rows);
21024
+ });
21025
+ }
21026
+ fetchMore(opts) {
21027
+ const _super = Object.create(null, {
21028
+ updateDatasource: { get: () => super.updateDatasource }
21029
+ });
21030
+ return __awaiter(this, void 0, void 0, function* () {
21031
+ if (!this._fetchMoreFn)
21032
+ return false; // Avoid multiple call
21033
+ if (this._editingRowCount > 0) {
21034
+ console.warn('Cannot fetch more because still editing row');
21035
+ return;
21036
+ }
21037
+ // Fetch next page
21038
+ this._fetchMoreFn = null; // Avoid multiple call
21039
+ const res = yield this._fetchMoreFn();
21040
+ // Skip if empty (no more data)
21041
+ if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
21042
+ return false;
21043
+ // Update the data source
21044
+ const existingData = yield this.getData();
21045
+ _super.updateDatasource.call(this, existingData.concat(...res.data), opts);
21046
+ // Remember fetchMore
21047
+ this._fetchMoreFn = res.fetchMore;
21048
+ return true;
21049
+ });
21050
+ }
20746
21051
  /* -- protected method -- */
20747
21052
  markAsLoading() {
20748
21053
  if (this.loadingSubject.value !== true) {
@@ -21088,7 +21393,12 @@ class AppTable {
21088
21393
  combineLatest([
21089
21394
  this.onStartEditingRow,
21090
21395
  this._destroy$
21091
- ])), map(() => { var _a; return (_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty; }), filter(dirty => dirty === true), first())))
21396
+ ])
21397
+ // DEBUG
21398
+ //.pipe(
21399
+ // tap(() => console.debug('TODO stopping previous row listener'))
21400
+ //)
21401
+ ), map(() => { var _a; return (_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty; }), filter(dirty => dirty === true), first())))
21092
21402
  .subscribe(() => this.markAsDirty()));
21093
21403
  // Call datasource refresh, on each refresh events
21094
21404
  this.registerSubscription(this.onRefresh
@@ -22325,13 +22635,25 @@ class AppEditor {
22325
22635
  this._subscription = new Subscription();
22326
22636
  this._enabled = false;
22327
22637
  this._dirty = false;
22328
- this._loading = true;
22329
22638
  this._$ready = new BehaviorSubject(false);
22639
+ this._$loading = new BehaviorSubject(true);
22330
22640
  this.debug = false;
22331
22641
  this.submitted = false;
22332
22642
  this.toolbar = null;
22333
22643
  this.formButtonsBar = null;
22334
22644
  }
22645
+ /**
22646
+ * @deprecated
22647
+ */
22648
+ set _loading(value) {
22649
+ this._$loading.next(value);
22650
+ }
22651
+ /**
22652
+ * @deprecated
22653
+ */
22654
+ get _loading() {
22655
+ return this._$loading.value;
22656
+ }
22335
22657
  get tables() {
22336
22658
  return this._children && this._children.filter(c => c instanceof AppTable);
22337
22659
  }
@@ -22359,7 +22681,7 @@ class AppEditor {
22359
22681
  }
22360
22682
  get loading() {
22361
22683
  var _a;
22362
- return this._loading || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
22684
+ return this._$loading.value || (((_a = this._children) === null || _a === void 0 ? void 0 : _a.findIndex(c => c.enabled && c.loading)) !== -1) || false;
22363
22685
  }
22364
22686
  get enabled() {
22365
22687
  return this._enabled;
@@ -22385,6 +22707,8 @@ class AppEditor {
22385
22707
  this._subscription.unsubscribe();
22386
22708
  this._$ready.complete();
22387
22709
  this._$ready.unsubscribe();
22710
+ this._$loading.complete();
22711
+ this._$loading.unsubscribe();
22388
22712
  }
22389
22713
  addChildForm(form) {
22390
22714
  if (!form)
@@ -24572,5 +24896,5 @@ const ErrorCodes = {
24572
24896
  * Generated bundle index. Do not edit.
24573
24897
  */
24574
24898
 
24575
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileService, FileSizePipe, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialChipsModule, MaterialTestingModule, MaterialTestingPage, MathAbsPipe, MenuComponent, MenuItems, MenuService, ModalToolbarComponent, NetworkService, NgInitDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialRef, ReferentialUtils, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedValidators, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UserEvent, UserEventFilter, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isControlHasInput, isEmptyArray, isInputElement, isInstanceOf, isInt, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0$5 as ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, SharedMatBadgeIconModule as ɵc, MatBadgeIconDirective as ɵd, isFocusableElement as ɵe, MatBadgeIconTestPage as ɵf, RegisterForm as ɵg, AccountValidatorService as ɵh, RegisterModal as ɵi, UserSettingsValidatorService as ɵj, LocalSettingsValidatorService as ɵk, AppIconComponent as ɵl };
24899
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileService, FileSizePipe, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialChipsModule, MaterialTestingModule, MaterialTestingPage, MathAbsPipe, MenuComponent, MenuItems, MenuService, ModalToolbarComponent, NetworkService, NgInitDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialRef, ReferentialUtils, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedValidators, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UserEvent, UserEventFilter, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isControlHasInput, isEmptyArray, isInputElement, isInstanceOf, isInt, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0$5 as ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, SharedMatBadgeIconModule as ɵc, MatBadgeIconDirective as ɵd, isFocusableElement as ɵe, MatBadgeIconTestPage as ɵf, RegisterForm as ɵg, AccountValidatorService as ɵh, RegisterModal as ɵi, UserSettingsValidatorService as ɵj, LocalSettingsValidatorService as ɵk, AppIconComponent as ɵl };
24576
24900
  //# sourceMappingURL=sumaris-net.ngx-components.js.map