@sumaris-net/ngx-components 1.6.1 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +672 -297
  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 +13 -0
  6. package/esm2015/src/app/core/auth/modal/modal-auth.js +21 -9
  7. package/esm2015/src/app/core/table/entities-table-datasource.class.js +9 -3
  8. package/esm2015/src/app/shared/form/field.model.js +1 -1
  9. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +143 -122
  10. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +6 -6
  11. package/esm2015/src/app/shared/material/chips/material.chips.js +372 -94
  12. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +54 -18
  13. package/esm2015/src/app/shared/material/swipe/material.swipe.js +5 -5
  14. package/esm2015/src/app/shared/material/swipe/testing/swipe.test.js +2 -2
  15. package/fesm2015/sumaris-net.ngx-components.js +624 -274
  16. package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
  17. package/package.json +1 -1
  18. package/src/app/core/auth/modal/modal-auth.d.ts +12 -5
  19. package/src/app/core/table/entities-table-datasource.class.d.ts +1 -1
  20. package/src/app/shared/form/field.model.d.ts +2 -1
  21. package/src/app/shared/material/autocomplete/material.autocomplete.d.ts +39 -38
  22. package/src/app/shared/material/autocomplete/testing/autocomplete.test.d.ts +4 -5
  23. package/src/app/shared/material/chips/material.chips.d.ts +42 -13
  24. package/src/app/shared/material/chips/testing/chips.test.d.ts +1 -1
  25. package/src/app/shared/material/swipe/material.swipe.d.ts +2 -2
  26. package/src/theme/_ngx-components.scss +3 -1
  27. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -1262,11 +1262,11 @@
1262
1262
  var attributesOrFn = attributes.map(function (a, index) { return typeof a === 'function' && options.attributes[index] || a; });
1263
1263
  var filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
1264
1264
  var displayWith = options.displayWith || (function (obj) { return obj && joinPropertiesPath(obj, attributes); });
1265
- var compareWith = options.compareWith || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
1265
+ var equals = options.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
1266
1266
  var config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn: suggestFn,
1267
1267
  filter: filter,
1268
1268
  displayWith: displayWith,
1269
- compareWith: compareWith });
1269
+ equals: equals });
1270
1270
  this.fields[fieldName] = config;
1271
1271
  return config;
1272
1272
  };
@@ -1278,27 +1278,14 @@
1278
1278
  };
1279
1279
  return MatAutocompleteConfigHolder;
1280
1280
  }());
1281
- var DEFAULT_VALUE_ACCESSOR$6 = {
1282
- provide: i1.NG_VALUE_ACCESSOR,
1283
- useExisting: i0.forwardRef(function () { return MatAutocompleteField; }),
1284
- multi: true
1285
- };
1286
- var noop$7 = function () { };
1287
- var ɵ0$a = noop$7;
1281
+ var noop$8 = function (_) { };
1282
+ var ɵ0$b = noop$8;
1288
1283
  var MatAutocompleteField = /** @class */ (function () {
1289
1284
  function MatAutocompleteField(cd, formGroupDir) {
1290
1285
  this.cd = cd;
1291
1286
  this.formGroupDir = formGroupDir;
1292
- this._onChangeCallback = noop$7;
1293
- this._onTouchedCallback = noop$7;
1294
- this._subscription = new rxjs.Subscription();
1295
- this._filter$ = new rxjs.BehaviorSubject(undefined);
1296
- this._reload$ = new rxjs.Subject();
1297
- this._readonly = false;
1298
- this.$inputItems = new rxjs.BehaviorSubject(undefined);
1299
- this.$filteredItems = new rxjs.BehaviorSubject(undefined);
1300
- this.displayValue = '';
1301
- this._fetchMore$ = new i0.EventEmitter();
1287
+ this._onChangeCallback = noop$8;
1288
+ this._onTouchedCallback = noop$8;
1302
1289
  this.logPrefix = '[mat-autocomplete] ';
1303
1290
  this.formControlName = null;
1304
1291
  this.required = false;
@@ -1311,13 +1298,21 @@
1311
1298
  this.fetchMoreThreshold = '15%';
1312
1299
  this.suggestLengthThreshold = null;
1313
1300
  this.showLoadingSpinner = true;
1314
- this.animationsDisabled = true;
1315
- this.onClick = new i0.EventEmitter();
1316
- this.onBlur = new i0.EventEmitter();
1317
- this.onFocus = new i0.EventEmitter();
1318
- this.onDropButtonClick = new i0.EventEmitter(true);
1319
- this.onKeydownEscape = new i0.EventEmitter();
1320
- this.onKeyupEnter = new i0.EventEmitter();
1301
+ this.debug = false;
1302
+ this.clicked = new i0.EventEmitter();
1303
+ this.blurred = new i0.EventEmitter();
1304
+ this.focused = new i0.EventEmitter();
1305
+ this.dropButtonClick = new i0.EventEmitter(true);
1306
+ this.keydownEscape = new i0.EventEmitter();
1307
+ this.keyupEnter = new i0.EventEmitter();
1308
+ this._readonly = false;
1309
+ this.$inputItems = new rxjs.BehaviorSubject(undefined);
1310
+ this.$filteredItems = new rxjs.BehaviorSubject(undefined);
1311
+ this.displayValue = '';
1312
+ this._fetchMore$ = new i0.EventEmitter();
1313
+ this._subscription = new rxjs.Subscription();
1314
+ this._$filter = new rxjs.BehaviorSubject(undefined);
1315
+ this._reload$ = new rxjs.Subject();
1321
1316
  }
1322
1317
  Object.defineProperty(MatAutocompleteField.prototype, "itemCount", {
1323
1318
  get: function () {
@@ -1335,13 +1330,13 @@
1335
1330
  });
1336
1331
  Object.defineProperty(MatAutocompleteField.prototype, "filter", {
1337
1332
  get: function () {
1338
- return this._filter$.value;
1333
+ return this._$filter.value;
1339
1334
  },
1340
1335
  set: function (value) {
1341
- if (value !== this._filter$.value) {
1336
+ if (value !== this._$filter.value) {
1342
1337
  // DEBUG
1343
1338
  //console.debug(this.logPrefix + " Setting filter:", value);
1344
- this._filter$.next(value);
1339
+ this._$filter.next(value);
1345
1340
  }
1346
1341
  },
1347
1342
  enumerable: false,
@@ -1417,6 +1412,13 @@
1417
1412
  enumerable: false,
1418
1413
  configurable: true
1419
1414
  });
1415
+ Object.defineProperty(MatAutocompleteField.prototype, "loading", {
1416
+ get: function () {
1417
+ return isNil(this.$filteredItems.value);
1418
+ },
1419
+ enumerable: false,
1420
+ configurable: true
1421
+ });
1420
1422
  MatAutocompleteField.prototype.ngOnInit = function () {
1421
1423
  var _this = this;
1422
1424
  var _a, _b;
@@ -1434,10 +1436,11 @@
1434
1436
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
1435
1437
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
1436
1438
  this.displayWith = this.displayWith || this.config.displayWith;
1439
+ this.equals = this.equals || this.config.equals;
1437
1440
  this.mobile = toBoolean(this.mobile, this.config.mobile);
1438
1441
  this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
1439
1442
  this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
1440
- this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus));
1443
+ this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus, true));
1441
1444
  this.classList = this.classList || this.config.class;
1442
1445
  this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
1443
1446
  this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
@@ -1448,21 +1451,18 @@
1448
1451
  this.displayColumnSizes = this.displayColumnSizes
1449
1452
  // if only column: auto size
1450
1453
  || (this.displayAttributes.length === 1 && [undefined])
1451
- || this.displayAttributes.map(function (attr) {
1452
- // If label, set col size = 2
1453
- return (attr && attr.endsWith('label')) ? 2 :
1454
- // If rankOrder => col size = 1
1455
- ((attr && attr.endsWith('rankOrder')) ? 1
1456
- // Else => auto size
1457
- : undefined);
1458
- });
1454
+ // Computed column size:
1455
+ // - if label then col size = 2
1456
+ // - if rankOrder then col size = 1
1457
+ // - ese => auto size
1458
+ || this.displayAttributes.map(function (attr) { return (attr && attr.endsWith('label')) ? 2
1459
+ : ((attr && attr.endsWith('rankOrder')) ? 1
1460
+ : undefined); });
1459
1461
  this.displayColumnNames = this.displayAttributes.map(function (attr, index) { return _this.displayColumnNames && _this.displayColumnNames[index] ||
1460
1462
  (_this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()); });
1461
1463
  this.mobile = toBoolean(this.mobile, false);
1462
1464
  this.searchable = !this.mobile && !this.multiple;
1463
- // Default comparator (only need when using mat-select)
1464
- if (!this.searchable && !this.compareWith)
1465
- this.compareWith = function (o1, o2) { return o1 && o2 && o1.id === o2.id; };
1465
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
1466
1466
  var classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
1467
1467
  this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
1468
1468
  || (classList.includes('min-width-large') && '400px')
@@ -1478,7 +1478,7 @@
1478
1478
  var suggestFromArrayFn_1 = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
1479
1479
  return __generator(this, function (_e) {
1480
1480
  // DEBUG
1481
- //console.debug(this.logPrefix + " Calling suggestFromArray with value=", value);
1481
+ //console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
1482
1482
  return [2 /*return*/, suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter))];
1483
1483
  });
1484
1484
  }); };
@@ -1505,10 +1505,18 @@
1505
1505
  }
1506
1506
  else if (!this.searchable) {
1507
1507
  // Manually fill input items, from the given suggest function
1508
- this._subscription.add(this._filter$.pipe(operators.startWith(this.filter), operators.debounceTime(250), operators.takeWhile(function (_) { return !_this.searchable; }), // Close subscription, when enabling search (no more mat-select)
1508
+ this._subscription.add(this._$filter.pipe(operators.startWith(this.filter), operators.debounceTime(250), operators.takeWhile(function (_) { return !_this.searchable; }), // Close subscription, when enabling search (no more mat-select)
1509
1509
  operators.switchMap(function (filter) { return _this.suggest('*', filter); }))
1510
1510
  .subscribe(function (items) { return _this.$inputItems.next(items); }));
1511
1511
  }
1512
+ // Send value to suggest when :
1513
+ // - is nil and '*', and no min length threshold
1514
+ // - is not nil and not a string type (e.g. object)
1515
+ // - is not nil and is a string, and has enough character
1516
+ var thresholdFilterFn = function (value) { return (isNilOrBlank(value) || (value === '*')
1517
+ ? (_this.suggestLengthThreshold <= 0)
1518
+ : (!(typeof value === 'string')
1519
+ || value.length >= _this.suggestLengthThreshold)); };
1512
1520
  var filteredItemsChanges = rxjs.merge(
1513
1521
  // Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
1514
1522
  this._reload$,
@@ -1516,23 +1524,19 @@
1516
1524
  this.formControl.valueChanges
1517
1525
  .pipe(operators.filter(function (value) { return _this.enabled && _this.searchable && isNotNilString(value); }),
1518
1526
  // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
1519
- operators.tap(function (value) {
1520
- if (_this.showLoadingSpinner) {
1521
- _this.markAsLoading();
1522
- }
1523
- }),
1527
+ operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
1524
1528
  // Filter if not enough character
1525
1529
  operators.filter(function (value) { return value.length >= _this.suggestLengthThreshold; }),
1526
1530
  // Wait a debounce time
1527
- operators.debounceTime(this.debounceTime)
1531
+ operators.debounceTime(this.debounceTime),
1528
1532
  // DEBUG
1529
- //tap((value) => console.debug(this.logPrefix + ' Search text changes:', value)),
1530
- ),
1533
+ operators.tap(function (value) { return console.debug(_this.logPrefix + ' Search text changes:', value); })),
1531
1534
  // Object set: use it (no distinctUntilChanged() pipe need)
1532
1535
  this.formControl.valueChanges
1533
1536
  .pipe(operators.startWith(this.formControl.value), operators.filter(function (value) { return (_this.searchable && isNotNil(value) && typeof value === 'object'); }), operators.tap(function (value) {
1534
1537
  // DEBUG
1535
- //console.debug(this.logPrefix + ' object changes:', value)
1538
+ if (_this.debug)
1539
+ console.debug(_this.logPrefix + ' object changes:', value);
1536
1540
  // Update the display value (if need)
1537
1541
  var displayValue = _this.displayWith(value) || '';
1538
1542
  if (_this.displayValue !== displayValue) {
@@ -1542,37 +1546,35 @@
1542
1546
  _this.matInputText.nativeElement.value = _this.displayValue;
1543
1547
  }
1544
1548
  }
1545
- })
1549
+ }),
1546
1550
  // DEBUG
1547
- //tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
1548
- ),
1551
+ operators.tap(function (value) { return _this.debug && console.debug(_this.logPrefix + ' Received an object value: ', value); })),
1552
+ // On dropdown button click (no distinctUntilChanged(), nor debounceTime)
1553
+ this.dropButtonClick
1554
+ .pipe(operators.filter(function (event) { return _this.searchable && _this.enabled && (!event || !event.defaultPrevented); }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; }),
1555
+ // Make enough characters
1556
+ operators.filter(thresholdFilterFn)),
1549
1557
  // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
1550
1558
  rxjs.merge(
1551
1559
  // Focus or click => Load all
1552
- rxjs.merge(this.onFocus, this.onClick)
1553
- .pipe(operators.filter(function (_) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; })),
1554
- // On dropdown button click
1555
- this.onDropButtonClick
1556
- .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable && (!event || !event.defaultPrevented); }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; })), rxjs.merge(this.$inputItems, this._filter$)
1557
- .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.formControl.value; })))
1560
+ rxjs.merge(this.focused, this.clicked)
1561
+ .pipe(operators.filter(function (_) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; }),
1562
+ // DEBUG
1563
+ operators.tap(function (value) { return _this.debug && console.debug(_this.logPrefix + ' Received focused or clicked event: ', value); })), rxjs.merge(this.$inputItems, this._$filter)
1564
+ .pipe(operators.filter(function (_) { return _this.searchable && _this.enabled; }), operators.map(function (_) { return _this.formControl.value; }),
1565
+ // DEBUG
1566
+ operators.tap(function (value) { return _this.debug && console.debug(_this.logPrefix + ' Received $inputItems or filter event: ', value); })))
1558
1567
  .pipe(
1559
- // Start to suggest when :
1560
- // - '*'
1561
- // - is nil, and there is no min length threshold
1562
- // - is not nil and not a string type (e.g. object)
1563
- // - is not nil and is a string, and has enough character
1564
- operators.filter(function (value) { return value === '*'
1565
- || (isNil(value)
1566
- ? (_this.suggestLengthThreshold <= 0)
1567
- : (!(typeof value === 'string')
1568
- || value.length >= _this.suggestLengthThreshold)); }),
1568
+ // Make sure there is enough characters
1569
+ operators.filter(thresholdFilterFn),
1569
1570
  // Distinguish changes
1570
- operators.distinctUntilChanged()))
1571
+ // - do NOT filter if loading, to force update after a blur event
1572
+ operators.distinctUntilChanged(function (v1, v2) { return !_this.loading && (v1 === v2 || _this.equals(v1, v2)); })))
1571
1573
  .pipe(
1572
1574
  // Suggest values
1573
1575
  operators.mergeMap(function (value) { return _this.suggest(value, _this.filter); }),
1574
1576
  // DEBUG
1575
- //tap(items => console.debug(this.logPrefix + ' Received from suggest: ', items)),
1577
+ operators.tap(function (items) { return _this.debug && console.debug(_this.logPrefix + ' Received from suggest: ', items); }),
1576
1578
  // Store implicit value (will use it onBlur if not other value selected)
1577
1579
  operators.tap(function (items) { return _this.updateImplicitValue(items); }));
1578
1580
  // Fetch more events
@@ -1593,7 +1595,7 @@
1593
1595
  // Make sure control value is inside (mat-select)
1594
1596
  if (items && !_this.searchable) {
1595
1597
  var value_1 = _this.formControl.value;
1596
- if (isNotNil(value_1) && typeof value_1 === 'object' && items.findIndex(function (item) { return _this.compareWith(item, value_1); }) === -1) {
1598
+ if (isNotNil(value_1) && typeof value_1 === 'object' && items.findIndex(function (item) { return _this.equals(item, value_1); }) === -1) {
1597
1599
  // If form value is missing: add it to the list
1598
1600
  items = items.concat(value_1);
1599
1601
  }
@@ -1602,10 +1604,12 @@
1602
1604
  _this.$filteredItems.next(items);
1603
1605
  }));
1604
1606
  // Applying implicit value, on blur
1605
- this._subscription.add(this.onBlur
1607
+ this._subscription.add(this.blurred
1606
1608
  .pipe(
1607
1609
  // Skip if not searchable
1608
- operators.filter(function (_) { return _this.searchable; }), operators.map(function (_) { return _this.formControl.value; }))
1610
+ operators.filter(function (_) { return _this.searchable; }), operators.map(function (_) { return _this.formControl.value; }),
1611
+ // DEBUG
1612
+ operators.tap(function (value) { return console.debug(_this.logPrefix + ' Received blurred event: ', value); }))
1609
1613
  .subscribe(function (value) {
1610
1614
  // When leave component without object, use implicit value if :
1611
1615
  // - an explicit value
@@ -1616,12 +1620,14 @@
1616
1620
  _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
1617
1621
  _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
1618
1622
  _this.checkIfTouched();
1623
+ _this.$filteredItems.next([_this._implicitValue]);
1619
1624
  }
1620
1625
  else if (isNilOrBlank(value)) {
1621
1626
  _this.writeValue(null);
1622
1627
  _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
1623
1628
  _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
1624
1629
  _this.checkIfTouched();
1630
+ _this.$filteredItems.next(undefined);
1625
1631
  }
1626
1632
  _this._implicitValue = null; // reset the implicit value
1627
1633
  }));
@@ -1632,7 +1638,7 @@
1632
1638
  operators.distinctUntilChanged())
1633
1639
  // Update component state
1634
1640
  .subscribe(function () { return _this.checkIfTouched(); }));
1635
- this._subscription.add(this.onKeydownEscape.subscribe(function (event) {
1641
+ this._subscription.add(this.keydownEscape.subscribe(function (event) {
1636
1642
  if (_this.isOpen) {
1637
1643
  event === null || event === void 0 ? void 0 : event.stopPropagation();
1638
1644
  event === null || event === void 0 ? void 0 : event.preventDefault();
@@ -1651,20 +1657,22 @@
1651
1657
  this._openedSubscription.unsubscribe();
1652
1658
  }
1653
1659
  this.$inputItems.complete();
1660
+ this.$inputItems.unsubscribe();
1654
1661
  this.$filteredItems.complete();
1662
+ this.$filteredItems.unsubscribe();
1655
1663
  this._reload$.complete();
1656
- this._filter$.complete();
1657
- this.onDropButtonClick.complete();
1658
- this.onClick.complete();
1659
- this.onBlur.complete();
1660
- this.onFocus.complete();
1661
- this.onKeydownEscape.complete();
1662
- this.onKeyupEnter.complete();
1664
+ this._$filter.complete();
1665
+ this.dropButtonClick.complete();
1666
+ this.clicked.complete();
1667
+ this.blurred.complete();
1668
+ this.focused.complete();
1669
+ this.keydownEscape.complete();
1670
+ this.keyupEnter.complete();
1663
1671
  this._fetchMore$.complete();
1664
1672
  this._implicitValue = undefined;
1665
1673
  this.formControl = null;
1666
1674
  this.displayWith = null;
1667
- this.compareWith = null;
1675
+ this.equals = null;
1668
1676
  this.suggestFn = null;
1669
1677
  this.$filteredItems = null;
1670
1678
  this.matSelectItems$ = null;
@@ -1674,8 +1682,8 @@
1674
1682
  this._onTouchedCallback = null;
1675
1683
  this._onFetchMoreCallback = null;
1676
1684
  // Destroy the 'autocomplete' instance, to avoid memory leak
1677
- if (this.matAutocomplete) {
1678
- this.matAutocomplete.ngOnDestroy();
1685
+ if (this.autocomplete) {
1686
+ this.autocomplete.ngOnDestroy();
1679
1687
  }
1680
1688
  };
1681
1689
  /**
@@ -1687,7 +1695,7 @@
1687
1695
  };
1688
1696
  MatAutocompleteField.prototype.writeValue = function (value) {
1689
1697
  // DEBUG
1690
- // console.debug(this.logPrefix + " Writing value: ", value);
1698
+ // console.debug(this.logPrefix + ' Writing value: ', value);
1691
1699
  if (value !== this.formControl.value) {
1692
1700
  this.formControl.patchValue(value, { emitEvent: false });
1693
1701
  this._onChangeCallback(value);
@@ -1701,7 +1709,7 @@
1701
1709
  };
1702
1710
  MatAutocompleteField.prototype.setDisabledState = function (isDisabled) {
1703
1711
  var _a;
1704
- if (isDisabled && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1712
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1705
1713
  this.closePanel();
1706
1714
  }
1707
1715
  this.cd.markForCheck();
@@ -1715,7 +1723,7 @@
1715
1723
  (_a = this.matSelect) === null || _a === void 0 ? void 0 : _a.focus();
1716
1724
  }
1717
1725
  };
1718
- MatAutocompleteField.prototype.filterInputTextFocusInEvent = function (event) {
1726
+ MatAutocompleteField.prototype.filterInputTextFocusEvent = function (event) {
1719
1727
  if (!event || event.defaultPrevented)
1720
1728
  return;
1721
1729
  // Ignore event from mat-option
@@ -1724,15 +1732,20 @@
1724
1732
  if (event.stopPropagation)
1725
1733
  event.stopPropagation();
1726
1734
  event.returnValue = false;
1727
- //DEBUG console.debug(this.logPrefix + " Cancelling focus event");
1735
+ // DEBUG
1736
+ if (this.debug)
1737
+ console.debug(this.logPrefix + ' Cancelling focus event');
1728
1738
  return false;
1729
1739
  }
1730
- var hasContent = selectInputContent(event);
1740
+ if (this.debug)
1741
+ console.debug(this.logPrefix + ' Select input content');
1742
+ var hasContent = true; // selectInputContent(event);
1731
1743
  // If combo is empty, or if has content but should force to show panel on focus
1732
- if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
1744
+ if (!hasContent || this.showPanelOnFocus || this.showAllOnFocus) {
1733
1745
  // DEBUG
1734
- //console.debug(this.logPrefix + ' Emit focus event');
1735
- this.onFocus.emit(event);
1746
+ if (this.debug)
1747
+ console.debug(this.logPrefix + ' Emit focus event');
1748
+ this.focused.emit();
1736
1749
  return true;
1737
1750
  }
1738
1751
  return false;
@@ -1746,14 +1759,17 @@
1746
1759
  if (event.stopPropagation)
1747
1760
  event.stopPropagation();
1748
1761
  event.returnValue = false;
1749
- //DEBUG console.debug(this.logPrefix + " Cancelling blur event");
1762
+ // DEBUG
1763
+ if (this.debug)
1764
+ console.debug(this.logPrefix + " Cancelling blur event");
1750
1765
  return false;
1751
1766
  }
1752
1767
  //DEBUG
1753
- //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
1768
+ if (this.debug)
1769
+ console.debug(this.logPrefix + ' Blur: move caret to the beginning');
1754
1770
  // Move caret to the beginning (fix issue IMAGINE-469)
1755
1771
  selectInputRange(event.target, 0, 0);
1756
- this.onBlur.emit(event);
1772
+ this.blurred.emit(event);
1757
1773
  return true;
1758
1774
  };
1759
1775
  MatAutocompleteField.prototype.filterMatSelectFocusEvent = function (event) {
@@ -1761,7 +1777,7 @@
1761
1777
  return;
1762
1778
  // DEBUG
1763
1779
  // console.debug(this.logPrefix + " Received <mat-select> focus event", event);
1764
- this.onFocus.emit(event);
1780
+ this.focused.emit(event);
1765
1781
  };
1766
1782
  MatAutocompleteField.prototype.filterMatSelectBlurEvent = function (event) {
1767
1783
  if (!event || event.defaultPrevented)
@@ -1778,7 +1794,7 @@
1778
1794
  // console.debug(this.logPrefix + " Cancelling <mat-select> blur event");
1779
1795
  return false;
1780
1796
  }
1781
- this.onBlur.emit(event);
1797
+ this.blurred.emit(event);
1782
1798
  return true;
1783
1799
  };
1784
1800
  MatAutocompleteField.prototype.toggleSearch = function (event) {
@@ -1801,7 +1817,7 @@
1801
1817
  };
1802
1818
  MatAutocompleteField.prototype._initAutocompleteInfiniteScroll = function (threshold) {
1803
1819
  var _this = this;
1804
- if (!this.matAutocomplete)
1820
+ if (!this.autocomplete)
1805
1821
  return; // Skip
1806
1822
  // DEBUG
1807
1823
  //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
@@ -1809,12 +1825,12 @@
1809
1825
  this._openedSubscription.unsubscribe();
1810
1826
  this._subscription.remove(this._openedSubscription);
1811
1827
  }
1812
- var opened$ = this.matAutocomplete._isOpen
1828
+ var opened$ = this.autocomplete._isOpen
1813
1829
  ? rxjs.timer(0)
1814
- : this.matAutocomplete.opened.pipe(operators.debounceTime(200));
1830
+ : this.autocomplete.opened.pipe(operators.debounceTime(200));
1815
1831
  var scrollEnd$ = opened$
1816
1832
  .pipe(operators.map(function (_) { return _this.getAutocompletePanel(); }), operators.filter(isNotNil), operators.switchMap(function (panel) { return fromScrollEndEvent(panel, threshold)
1817
- .pipe(operators.takeUntil(_this.matAutocomplete.closed)); }));
1833
+ .pipe(operators.takeUntil(_this.autocomplete.closed)); }));
1818
1834
  // Trigger fetch more, end end scroll reached
1819
1835
  this._openedSubscription = scrollEnd$
1820
1836
  .subscribe(function () { return _this._fetchMore$.emit(); });
@@ -1847,7 +1863,7 @@
1847
1863
  Object.defineProperty(MatAutocompleteField.prototype, "isOpen", {
1848
1864
  get: function () {
1849
1865
  var _a, _b;
1850
- return (this.searchable && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1866
+ return (this.searchable && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1851
1867
  || ((_b = this.matSelect) === null || _b === void 0 ? void 0 : _b.panelOpen)
1852
1868
  || false;
1853
1869
  },
@@ -1856,8 +1872,8 @@
1856
1872
  });
1857
1873
  MatAutocompleteField.prototype.closePanel = function () {
1858
1874
  var _a, _b, _c, _d;
1859
- if ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
1860
- (_b = this.matAutocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
1875
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
1876
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
1861
1877
  return;
1862
1878
  }
1863
1879
  if ((_c = this.matSelect) === null || _c === void 0 ? void 0 : _c.panelOpen) {
@@ -1892,6 +1908,9 @@
1892
1908
  this._moreItemsCount = fetchMore && (this._itemCount - data.length) || 0;
1893
1909
  res = data;
1894
1910
  }
1911
+ // DEBUG
1912
+ if (this.debug)
1913
+ console.debug(this.logPrefix + ' Filtered items by suggestFn:', value, res);
1895
1914
  return [2 /*return*/, res];
1896
1915
  }
1897
1916
  });
@@ -1938,7 +1957,7 @@
1938
1957
  };
1939
1958
  MatAutocompleteField.prototype.getAutocompletePanel = function () {
1940
1959
  var _a, _b;
1941
- var ele = (_b = (_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
1960
+ var ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
1942
1961
  if (!ele) {
1943
1962
  // DEBUG
1944
1963
  console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
@@ -1973,10 +1992,14 @@
1973
1992
  { type: i0.Component, args: [{
1974
1993
  // eslint-disable-next-line @angular-eslint/component-selector
1975
1994
  selector: 'mat-autocomplete-field',
1976
- 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",
1977
- providers: [DEFAULT_VALUE_ACCESSOR$6],
1995
+ 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)=\"dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\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",
1996
+ providers: [{
1997
+ provide: i1.NG_VALUE_ACCESSOR,
1998
+ multi: true,
1999
+ useExisting: i0.forwardRef(function () { return MatAutocompleteField; })
2000
+ }],
1978
2001
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
1979
- 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}"]
2002
+ 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%}"]
1980
2003
  },] }
1981
2004
  ];
1982
2005
  MatAutocompleteField.ctorParameters = function () { return [
@@ -1984,7 +2007,7 @@
1984
2007
  { type: i1.FormGroupDirective, decorators: [{ type: i0.Optional }] }
1985
2008
  ]; };
1986
2009
  MatAutocompleteField.propDecorators = {
1987
- compareWith: [{ type: i0.Input }],
2010
+ equals: [{ type: i0.Input }],
1988
2011
  logPrefix: [{ type: i0.Input }],
1989
2012
  formControl: [{ type: i0.Input }],
1990
2013
  formControlName: [{ type: i0.Input }],
@@ -2014,21 +2037,21 @@
2014
2037
  fetchMoreThreshold: [{ type: i0.Input }],
2015
2038
  suggestLengthThreshold: [{ type: i0.Input }],
2016
2039
  showLoadingSpinner: [{ type: i0.Input }],
2017
- animationsDisabled: [{ type: i0.HostBinding, args: ['@.disabled',] }],
2040
+ debug: [{ type: i0.Input }],
2041
+ clicked: [{ type: i0.Output, args: ['click',] }],
2042
+ blurred: [{ type: i0.Output, args: ['blur',] }],
2043
+ focused: [{ type: i0.Output, args: ['focus',] }],
2044
+ dropButtonClick: [{ type: i0.Output }],
2045
+ keydownEscape: [{ type: i0.Output, args: ['keydown.escape',] }],
2046
+ keyupEnter: [{ type: i0.Output, args: ['keyup.enter',] }],
2047
+ matSelect: [{ type: i0.ViewChild, args: ['matSelect',] }],
2048
+ matInputText: [{ type: i0.ViewChild, args: ['matInputText',] }],
2049
+ autocomplete: [{ type: i0.ViewChild, args: [autocomplete.MatAutocomplete,] }],
2050
+ autocompleteTrigger: [{ type: i0.ViewChild, args: [autocomplete.MatAutocompleteTrigger,] }],
2018
2051
  filter: [{ type: i0.Input }],
2019
2052
  readonly: [{ type: i0.Input }],
2020
2053
  tabindex: [{ type: i0.Input }],
2021
- items: [{ type: i0.Input }],
2022
- onClick: [{ type: i0.Output, args: ['click',] }],
2023
- onBlur: [{ type: i0.Output, args: ['blur',] }],
2024
- onFocus: [{ type: i0.Output, args: ['focus',] }],
2025
- onDropButtonClick: [{ type: i0.Output, args: ['dropButtonClick',] }],
2026
- onKeydownEscape: [{ type: i0.Output, args: ['keydown.escape',] }],
2027
- onKeyupEnter: [{ type: i0.Output, args: ['keyup.enter',] }],
2028
- matSelect: [{ type: i0.ViewChild, args: ['matSelect',] }],
2029
- matInputText: [{ type: i0.ViewChild, args: ['matInputText',] }],
2030
- matAutocomplete: [{ type: i0.ViewChild, args: [autocomplete.MatAutocomplete,] }],
2031
- matAutocompleteTrigger: [{ type: i0.ViewChild, args: [autocomplete.MatAutocompleteTrigger,] }]
2054
+ items: [{ type: i0.Input }]
2032
2055
  };
2033
2056
 
2034
2057
  var DateFormatPipe = /** @class */ (function () {
@@ -4647,9 +4670,9 @@
4647
4670
  DD: [/[+-]/, /\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, /\d/, /\d/, /\d/, /\d/, '°']
4648
4671
  }
4649
4672
  };
4650
- var noop$6 = function () {
4673
+ var noop$7 = function () {
4651
4674
  };
4652
- var ɵ0$9 = noop$6;
4675
+ var ɵ0$a = noop$7;
4653
4676
  var MatLatLongField = /** @class */ (function () {
4654
4677
  function MatLatLongField(platform, translate, formBuilder, cd, formGroupDir) {
4655
4678
  this.platform = platform;
@@ -4657,8 +4680,8 @@
4657
4680
  this.formBuilder = formBuilder;
4658
4681
  this.cd = cd;
4659
4682
  this.formGroupDir = formGroupDir;
4660
- this._onChangeCallback = noop$6;
4661
- this._onTouchedCallback = noop$6;
4683
+ this._onChangeCallback = noop$7;
4684
+ this._onTouchedCallback = noop$7;
4662
4685
  this._subscription = new rxjs.Subscription();
4663
4686
  this.disabling = false;
4664
4687
  this.writing = false;
@@ -5015,8 +5038,8 @@
5015
5038
  multi: true
5016
5039
  };
5017
5040
  var DAY_MASK$2 = [/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/];
5018
- var noop$5 = function () { };
5019
- var ɵ0$8 = noop$5;
5041
+ var noop$6 = function () { };
5042
+ var ɵ0$9 = noop$6;
5020
5043
  var MatDate = /** @class */ (function () {
5021
5044
  function MatDate(platform, dateAdapter, translate, formBuilder, cd, keyboard, formGroupDir) {
5022
5045
  this.dateAdapter = dateAdapter;
@@ -5025,8 +5048,8 @@
5025
5048
  this.cd = cd;
5026
5049
  this.keyboard = keyboard;
5027
5050
  this.formGroupDir = formGroupDir;
5028
- this._onChangeCallback = noop$5;
5029
- this._onTouchedCallback = noop$5;
5051
+ this._onChangeCallback = noop$6;
5052
+ this._onTouchedCallback = noop$6;
5030
5053
  this._subscription = new rxjs.Subscription();
5031
5054
  this.writing = true;
5032
5055
  this.disabling = false;
@@ -5340,9 +5363,9 @@
5340
5363
  var DAY_MASK$1 = [/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/];
5341
5364
  var HOUR_REGEXP = /^[012][0-9][:][012345][0-9]$/;
5342
5365
  var HOUR_MASK$1 = [/[012]/, /\d/, ':', /[012345]/, /\d/];
5343
- var noop$4 = function () {
5366
+ var noop$5 = function () {
5344
5367
  };
5345
- var ɵ0$7 = noop$4;
5368
+ var ɵ0$8 = noop$5;
5346
5369
  var MatDateTime = /** @class */ (function () {
5347
5370
  function MatDateTime(platform, dateAdapter, translate, formBuilder, keyboard, cd, formGroupDir) {
5348
5371
  this.platform = platform;
@@ -5352,8 +5375,8 @@
5352
5375
  this.keyboard = keyboard;
5353
5376
  this.cd = cd;
5354
5377
  this.formGroupDir = formGroupDir;
5355
- this._onChangeCallback = noop$4;
5356
- this._onTouchedCallback = noop$4;
5378
+ this._onChangeCallback = noop$5;
5379
+ this._onTouchedCallback = noop$5;
5357
5380
  this._subscription = new rxjs.Subscription();
5358
5381
  this.writing = true;
5359
5382
  this.disabling = false;
@@ -5756,9 +5779,9 @@
5756
5779
  multi: true
5757
5780
  };
5758
5781
  var DAY_MASK = [/\d/, /\d/, /\d/, /\d/];
5759
- var noop$3 = function () {
5782
+ var noop$4 = function () {
5760
5783
  };
5761
- var ɵ0$6 = noop$3;
5784
+ var ɵ0$7 = noop$4;
5762
5785
  var MatDateShort = /** @class */ (function () {
5763
5786
  function MatDateShort(platform, dateAdapter, translate, formBuilder, cd, keyboard, formGroupDir) {
5764
5787
  this.dateAdapter = dateAdapter;
@@ -5767,8 +5790,8 @@
5767
5790
  this.cd = cd;
5768
5791
  this.keyboard = keyboard;
5769
5792
  this.formGroupDir = formGroupDir;
5770
- this._onChangeCallback = noop$3;
5771
- this._onTouchedCallback = noop$3;
5793
+ this._onChangeCallback = noop$4;
5794
+ this._onTouchedCallback = noop$4;
5772
5795
  this.writing = true;
5773
5796
  this.disabling = false;
5774
5797
  this.dayMask = DAY_MASK;
@@ -6126,9 +6149,9 @@
6126
6149
  };
6127
6150
  var HOUR_TIME_PATTERN = /[0-9]\d\d:[0-5]\d/;
6128
6151
  var HOUR_MASK = [/\d/, /\d/, /\d/, ':', /[0-5]/, /\d/];
6129
- var noop$2 = function () {
6152
+ var noop$3 = function () {
6130
6153
  };
6131
- var ɵ0$5 = noop$2;
6154
+ var ɵ0$6 = noop$3;
6132
6155
  var MatDuration = /** @class */ (function () {
6133
6156
  function MatDuration(platform, dateAdapter, translate, formBuilder, cd, formGroupDir) {
6134
6157
  this.dateAdapter = dateAdapter;
@@ -6137,8 +6160,8 @@
6137
6160
  this.cd = cd;
6138
6161
  this.formGroupDir = formGroupDir;
6139
6162
  this._subscription = new rxjs.Subscription();
6140
- this._onChangeCallback = noop$2;
6141
- this._onTouchedCallback = noop$2;
6163
+ this._onChangeCallback = noop$3;
6164
+ this._onTouchedCallback = noop$3;
6142
6165
  this.writing = true;
6143
6166
  this.disabling = false;
6144
6167
  this.hourMask = HOUR_MASK;
@@ -6399,17 +6422,17 @@
6399
6422
  useExisting: i0.forwardRef(function () { return MatBooleanField; }),
6400
6423
  multi: true
6401
6424
  };
6402
- var noop$1 = function () {
6425
+ var noop$2 = function () {
6403
6426
  };
6404
- var ɵ0$4 = noop$1;
6427
+ var ɵ0$5 = noop$2;
6405
6428
  var MatBooleanField = /** @class */ (function () {
6406
6429
  function MatBooleanField(translate, formBuilder, cd, formGroupDir) {
6407
6430
  this.translate = translate;
6408
6431
  this.formBuilder = formBuilder;
6409
6432
  this.cd = cd;
6410
6433
  this.formGroupDir = formGroupDir;
6411
- this._onChangeCallback = noop$1;
6412
- this._onTouchedCallback = noop$1;
6434
+ this._onChangeCallback = noop$2;
6435
+ this._onTouchedCallback = noop$2;
6413
6436
  this._writing = false;
6414
6437
  this.showRadio = false;
6415
6438
  this.disabled = false;
@@ -7347,7 +7370,7 @@
7347
7370
  // Default values
7348
7371
  this.displayAttributes = this.displayAttributes || ['label', 'name'];
7349
7372
  this.displayWith = this.displayWith || (function (obj) { return obj && joinPropertiesPath(obj, _this.displayAttributes); });
7350
- this.compareWithFn = this.compareWithFn || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7373
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7351
7374
  this.mobile = toBoolean(this.mobile, false);
7352
7375
  };
7353
7376
  MatSwipeField.prototype.ngOnDestroy = function () {
@@ -7409,7 +7432,7 @@
7409
7432
  if (this._writing)
7410
7433
  return;
7411
7434
  this._writing = true;
7412
- if (!this.compareWithFn(value, this._value)) {
7435
+ if (!this.equals(value, this._value)) {
7413
7436
  this._value = value;
7414
7437
  this.showSlides = isNotNil(this._value);
7415
7438
  this.updateSlides();
@@ -7498,7 +7521,7 @@
7498
7521
  MatSwipeField.prototype.updateSlides = function () {
7499
7522
  var _this = this;
7500
7523
  if (this.showSlides) {
7501
- var itemIndex = (this.$items.getValue() || []).findIndex(function (value) { return _this.compareWithFn(value, _this._value); });
7524
+ var itemIndex = (this.$items.getValue() || []).findIndex(function (value) { return _this.equals(value, _this._value); });
7502
7525
  if (itemIndex >= 0) {
7503
7526
  this.slideTo(itemIndex);
7504
7527
  }
@@ -7585,7 +7608,7 @@
7585
7608
  required: [{ type: i0.Input }],
7586
7609
  mobile: [{ type: i0.Input }],
7587
7610
  clearable: [{ type: i0.Input }],
7588
- compareWithFn: [{ type: i0.Input }],
7611
+ equals: [{ type: i0.Input }],
7589
7612
  displayWith: [{ type: i0.Input }],
7590
7613
  displayAttributes: [{ type: i0.Input }],
7591
7614
  appAutofocus: [{ type: i0.Input }],
@@ -7627,30 +7650,41 @@
7627
7650
  },] }
7628
7651
  ];
7629
7652
 
7653
+ var noop$1 = function () { };
7654
+ var ɵ0$4 = noop$1;
7630
7655
  var MatChipsField = /** @class */ (function () {
7631
7656
  function MatChipsField(cd, formGroupDir) {
7632
7657
  this.cd = cd;
7633
7658
  this.formGroupDir = formGroupDir;
7634
- this._onChangeCallback = function (_) { };
7635
- this._onTouchedCallback = function () { };
7659
+ this._onChangeCallback = noop$1;
7660
+ this._onTouchedCallback = noop$1;
7636
7661
  this.logPrefix = '[mat-chips] ';
7662
+ this.formControlName = null;
7637
7663
  this.required = false;
7638
7664
  this.readonly = false;
7639
7665
  this.clearable = false;
7640
- this.debounceTime = 250;
7641
- this.highlightAccent = false;
7666
+ this.debounceTime = null;
7642
7667
  this.i18nPrefix = 'REFERENTIAL.';
7643
7668
  this.noResultMessage = 'COMMON.NO_RESULT';
7669
+ this.itemSize = '48px';
7670
+ this.fetchMoreThreshold = '15%';
7671
+ this.suggestLengthThreshold = null;
7672
+ this.showLoadingSpinner = true;
7673
+ this.chipColor = null;
7644
7674
  this.debug = false;
7645
7675
  this.clicked = new i0.EventEmitter();
7646
7676
  this.blurred = new i0.EventEmitter();
7647
7677
  this.focused = new i0.EventEmitter();
7678
+ this.dropButtonClick = new i0.EventEmitter(true);
7679
+ this.keydownEscape = new i0.EventEmitter();
7680
+ this.keyupEnter = new i0.EventEmitter();
7648
7681
  this.$inputItems = new rxjs.BehaviorSubject(undefined);
7649
- this.onDropButtonClick = new i0.EventEmitter(true);
7682
+ this.$filteredItems = new rxjs.BehaviorSubject(undefined);
7650
7683
  this.inputControl = new i1.FormControl();
7651
- this.getPropertyByPath = getPropertyByPath;
7684
+ this._fetchMore$ = new i0.EventEmitter();
7652
7685
  this._subscription = new rxjs.Subscription();
7653
7686
  this._$filter = new rxjs.BehaviorSubject(undefined);
7687
+ this._reload$ = new rxjs.Subject();
7654
7688
  }
7655
7689
  Object.defineProperty(MatChipsField.prototype, "itemCount", {
7656
7690
  get: function () {
@@ -7659,14 +7693,21 @@
7659
7693
  enumerable: false,
7660
7694
  configurable: true
7661
7695
  });
7696
+ Object.defineProperty(MatChipsField.prototype, "canFetchMore", {
7697
+ get: function () {
7698
+ return this._onFetchMoreCallback && this._moreItemsCount > 0;
7699
+ },
7700
+ enumerable: false,
7701
+ configurable: true
7702
+ });
7662
7703
  Object.defineProperty(MatChipsField.prototype, "filter", {
7663
7704
  get: function () {
7664
- return this._$filter.getValue();
7705
+ return this._$filter.value;
7665
7706
  },
7666
7707
  set: function (value) {
7667
- if (this.debug)
7668
- console.debug(this.logPrefix + ' Setting filter:', value);
7669
- if (value !== this._$filter.getValue()) {
7708
+ if (value !== this._$filter.value) {
7709
+ // DEBUG
7710
+ //console.debug(this.logPrefix + " Setting filter:", value);
7670
7711
  this._$filter.next(value);
7671
7712
  }
7672
7713
  },
@@ -7685,19 +7726,25 @@
7685
7726
  configurable: true
7686
7727
  });
7687
7728
  Object.defineProperty(MatChipsField.prototype, "items", {
7729
+ get: function () {
7730
+ return this.$inputItems;
7731
+ },
7688
7732
  set: function (value) {
7689
7733
  var _this = this;
7690
7734
  // Remove previous subscription on items, (if exits)
7691
7735
  if (this._itemsSubscription) {
7692
- console.warn('Items received twice !');
7736
+ console.warn(this.logPrefix + ' Items received twice !');
7693
7737
  this._subscription.remove(this._itemsSubscription);
7694
7738
  this._itemsSubscription.unsubscribe();
7695
7739
  }
7696
7740
  if (rxjs.isObservable(value)) {
7697
- this._itemsSubscription = this._subscription.add(value.subscribe(function (v) { return _this.$inputItems.next(v); }));
7741
+ this._itemsSubscription = this._subscription.add(value.subscribe(function (v) {
7742
+ //console.warn(this.logPrefix + " Received items: ", v);
7743
+ _this.$inputItems.next(v);
7744
+ }));
7698
7745
  }
7699
7746
  else {
7700
- if (value !== this.$inputItems.getValue()) {
7747
+ if (value !== this.$inputItems.value) {
7701
7748
  this.$inputItems.next(value);
7702
7749
  }
7703
7750
  }
@@ -7726,8 +7773,16 @@
7726
7773
  enumerable: false,
7727
7774
  configurable: true
7728
7775
  });
7776
+ Object.defineProperty(MatChipsField.prototype, "loading", {
7777
+ get: function () {
7778
+ return isNil(this.$filteredItems.value);
7779
+ },
7780
+ enumerable: false,
7781
+ configurable: true
7782
+ });
7729
7783
  MatChipsField.prototype.ngOnInit = function () {
7730
7784
  var _this = this;
7785
+ var _a, _b;
7731
7786
  this.formControl = this.formControl || this.formControlName && this.formGroupDir && this.formGroupDir.form.get(this.formControlName);
7732
7787
  if (!this.formControl)
7733
7788
  throw new Error('Missing mandatory attribute \'formControl\' or \'formControlName\' in <mat-chips-field>.');
@@ -7742,101 +7797,214 @@
7742
7797
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
7743
7798
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
7744
7799
  this.displayWith = this.displayWith || this.config.displayWith;
7745
- this.compareWith = this.compareWith || this.config.compareWith;
7800
+ this.equals = this.equals || this.config.equals;
7746
7801
  this.mobile = toBoolean(this.mobile, this.config.mobile);
7747
- this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, true));
7802
+ this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
7803
+ this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
7748
7804
  this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus, true));
7749
- this.class = this.class || this.config.class;
7805
+ this.classList = this.classList || this.config.class;
7806
+ this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
7807
+ this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
7750
7808
  }
7751
7809
  // Default values
7752
- this.displayAttributes = this.displayAttributes || (this.filter && this.filter.attributes) || ['label', 'name'];
7810
+ this.displayAttributes = this.displayAttributes || ((_a = this.filter) === null || _a === void 0 ? void 0 : _a.attributes) || ['label', 'name'];
7753
7811
  this.displayWith = this.displayWith || (function (obj) { return obj && joinPropertiesPath(obj, _this.displayAttributes); });
7754
- this.compareWith = this.compareWith || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7755
- this.displayColumnSizes = this.displayColumnSizes || this.displayAttributes.map(function (attr) { return (
7756
- // If label then col size = 2
7757
- attr && attr.endsWith('label')) ? 2 :
7758
- // If rankOrder then col size = 1
7759
- (attr && attr.endsWith('rankOrder') ? 1 :
7760
- // Else, auto size
7761
- undefined); });
7812
+ this.displayColumnSizes = this.displayColumnSizes
7813
+ // if only column: auto size
7814
+ || (this.displayAttributes.length === 1 && [undefined])
7815
+ // Computed column size:
7816
+ // - if label then col size = 2
7817
+ // - if rankOrder then col size = 1
7818
+ // - ese => auto size
7819
+ || this.displayAttributes.map(function (attr) { return (attr && attr.endsWith('label')) ? 2
7820
+ : ((attr && attr.endsWith('rankOrder')) ? 1
7821
+ : undefined); });
7762
7822
  this.displayColumnNames = this.displayAttributes.map(function (attr, index) { return _this.displayColumnNames && _this.displayColumnNames[index] ||
7763
7823
  (_this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()); });
7764
7824
  this.mobile = toBoolean(this.mobile, false);
7825
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7826
+ var classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
7827
+ this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
7828
+ || (classList.includes('min-width-large') && '400px')
7829
+ || (classList.includes('min-width-xlarge') && '450px')
7830
+ || (classList.includes('mat-autocomplete-panel-full-size') && '100vw')));
7831
+ this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, true);
7832
+ this.debounceTime = toNumber(this.debounceTime, 250);
7833
+ this.highlightAccent = toBoolean(this.highlightAccent, false);
7834
+ this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
7835
+ this.matAutocompletePosition = this.matAutocompletePosition || (this.mobile ? 'above' : 'auto'); // On mobile, set position to above (because of bottom keyboard)
7765
7836
  // No suggestFn: filter on the given items
7766
7837
  if (!this.suggestFn) {
7767
7838
  var suggestFromArrayFn_1 = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
7768
- var _a, data, total;
7769
- return __generator(this, function (_b) {
7770
- switch (_b.label) {
7771
- case 0:
7772
- if (this.debug)
7773
- console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
7774
- return [4 /*yield*/, suggestFromArray(this.$inputItems.getValue(), value, Object.assign({ searchAttributes: this.displayAttributes }, filter))];
7775
- case 1:
7776
- _a = _b.sent(), data = _a.data, total = _a.total;
7777
- this._itemCount = toNumber(total, data && data.length || 0);
7778
- return [2 /*return*/, { data: data, total: total }];
7779
- }
7839
+ return __generator(this, function (_c) {
7840
+ if (this.debug)
7841
+ console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
7842
+ return [2 /*return*/, suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter))];
7780
7843
  });
7781
7844
  }); };
7782
7845
  // Wait (once) that items are loaded, then call suggest from array fn
7783
7846
  this.suggestFn = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
7784
- return __generator(this, function (_a) {
7785
- switch (_a.label) {
7847
+ return __generator(this, function (_c) {
7848
+ switch (_c.label) {
7786
7849
  case 0:
7787
- if (!isNil(this.$inputItems.getValue())) return [3 /*break*/, 2];
7850
+ if (!isNil(this.$inputItems.value)) return [3 /*break*/, 2];
7788
7851
  if (this.debug)
7789
7852
  console.debug('[mat-chips] Waiting items to be set...');
7790
7853
  return [4 /*yield*/, firstNotNilPromise(this.$inputItems)];
7791
7854
  case 1:
7792
- _a.sent();
7855
+ _c.sent();
7793
7856
  if (this.debug)
7794
- console.debug('[mat-chips] Received items:', this.$inputItems.getValue());
7795
- _a.label = 2;
7857
+ console.debug('[mat-chips] Received items:', this.$inputItems.value);
7858
+ _c.label = 2;
7796
7859
  case 2:
7797
7860
  this.suggestFn = suggestFromArrayFn_1;
7798
- return [2 /*return*/, this.suggest(value, filter)]; // Loop
7861
+ return [2 /*return*/, this.suggestFn(value, filter)]; // Loop
7799
7862
  }
7800
7863
  });
7801
7864
  }); };
7802
7865
  }
7803
- // this.matSelectItems$ = this.$inputItems
7804
- // .pipe(
7805
- // filter(isNotNil),
7806
- // map((items) => {
7807
- // // Make sure control value is inside
7808
- // const value = this.inputControl.value;
7809
- // // If form value is missing: add it to the list
7810
- // if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.compareWith(item, value)) === -1) {
7811
- // // console.debug(this.logPrefix + " Add form value to items, because missed in items", value);
7812
- // return items.concat(value);
7813
- // }
7814
- // return items;
7815
- // })
7816
- // );
7817
- this._subscription.add(this.onDropButtonClick
7818
- .pipe(operators.filter(function (event) { return (!event || !event.defaultPrevented) && _this.formControl.enabled; }))
7819
- .subscribe(function () {
7820
- _this.matInputText.nativeElement.focus();
7821
- }));
7822
- var updateFilteredItemsEvents$ = rxjs.merge(
7866
+ // Send value to suggest when :
7867
+ // - is nil and '*', and no min length threshold
7868
+ // - is not nil and not a string type (e.g. object)
7869
+ // - is not nil and is a string, and has enough character
7870
+ var thresholdFilterFn = function (value) { return (isNilOrBlank(value) || (value === '*')
7871
+ ? (_this.suggestLengthThreshold <= 0)
7872
+ : (!(typeof value === 'string')
7873
+ || value.length >= _this.suggestLengthThreshold)); };
7874
+ var filteredItemsChanges = rxjs.merge(
7875
+ // Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
7876
+ this._reload$, this.inputControl.valueChanges
7877
+ .pipe(operators.filter(function (value) { return _this.enabled && isNotNilString(value); }),
7878
+ // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
7879
+ operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
7880
+ // Filter if not enough character
7881
+ operators.filter(function (value) { return value.length >= _this.suggestLengthThreshold; }),
7882
+ // Wait a debounce time
7883
+ operators.debounceTime(this.debounceTime)
7884
+ // DEBUG
7885
+ //tap((value) => console.debug(this.logPrefix + ' Search text changes:', value))
7886
+ ),
7887
+ // Object set: use it (no distinctUntilChanged() pipe need)
7888
+ this.inputControl.valueChanges
7889
+ .pipe(operators.startWith(this.inputControl.value), operators.filter(function (value) { return isNotNil(value) && typeof value === 'object'; }),
7890
+ // DEBUG
7891
+ operators.tap(function (value) { return _this.debug && console.debug(_this.logPrefix + ' Received an object value: ', value); })),
7892
+ // On dropdown button click (no distinctUntilChanged(), nor debounceTime)
7893
+ this.dropButtonClick
7894
+ .pipe(operators.filter(function (event) { return _this.enabled && (!event || !event.defaultPrevented); }), operators.tap(function (_) { return _this.matInputText.nativeElement.focus(); }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; }),
7895
+ // Make sure there is enough characters
7896
+ operators.filter(thresholdFilterFn)),
7897
+ // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
7898
+ rxjs.merge(
7823
7899
  // Focus or click => Load all
7824
7900
  rxjs.merge(this.focused, this.clicked)
7825
- .pipe(operators.filter(function (_) { return _this.enabled; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.inputControl.value; })), this.inputControl.valueChanges
7826
- .pipe(operators.startWith(this.inputControl.value), operators.filter(function (value) { return (isNotNil(value) && typeof value === 'object') || (isNotNilString(value) && !value.includes('**')); }), operators.tap(function (value) {
7827
- if (_this.debug)
7828
- console.debug(_this.logPrefix + ' valueChanges:', value);
7829
- }), operators.debounceTime(this.debounceTime)), this.$inputItems
7830
- .pipe(operators.map(function () { return _this.formControl.value; })), this._$filter
7831
- .pipe(operators.map(function () { return _this.formControl.value; })));
7832
- this.filteredItems$ = updateFilteredItemsEvents$
7833
- .pipe(operators.distinctUntilChanged(),
7834
- //tap(value => this.debug && console.debug(this.logPrefix + " Received update event: ", value)),
7835
- operators.switchMap(function (value) { return _this.suggest(value, _this.filter); }));
7901
+ .pipe(operators.filter(function (_) { return _this.enabled; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.inputControl.value; })), rxjs.merge(this.$inputItems, this._$filter)
7902
+ .pipe(operators.filter(function (_) { return _this.enabled; }), operators.map(function (_) { return _this.inputControl.value; })))
7903
+ .pipe(
7904
+ // Make sure there is enough characters
7905
+ operators.filter(thresholdFilterFn),
7906
+ // Distinguish changes
7907
+ operators.distinctUntilChanged()))
7908
+ .pipe(
7909
+ // Suggest values
7910
+ operators.mergeMap(function (value) { return _this.suggest(value, _this.filter); }),
7911
+ // DEBUG
7912
+ //tap(items => console.debug(this.logPrefix + ' Received from suggest: ', items)),
7913
+ // Store implicit value (will use it onBlur if not other value selected)
7914
+ operators.tap(function (items) { return _this.updateImplicitValue(items); }));
7915
+ // Fetch more events
7916
+ var fetchMoreItemsChanges = this._fetchMore$
7917
+ .pipe(operators.tap(function (event) { return event === null || event === void 0 ? void 0 : event.preventDefault(); }), // Avoid to close the mat-select
7918
+ operators.filter(function () { return _this.canFetchMore; }), operators.mergeMap(function () { return _this.fetchMore(); }),
7919
+ // DEBUG
7920
+ //tap(moreItems => console.debug(this.logPrefix + ' Received from fetch More: ', moreItems)),
7921
+ // Concat to existing items
7922
+ operators.map(function (moreItems) { return (_this.$filteredItems.value || []).concat(moreItems); }));
7923
+ // Update filtered items
7924
+ this._subscription.add(rxjs.merge(this.$inputItems,
7925
+ // Update items events
7926
+ filteredItemsChanges,
7927
+ // Fetch more events
7928
+ fetchMoreItemsChanges)
7929
+ // Emit items
7930
+ .subscribe(function (items) { return _this.$filteredItems.next(items); }));
7931
+ // Applying implicit value, on blur
7932
+ this._subscription.add(this.blurred
7933
+ .pipe(operators.map(function (_) { return _this.formControl.value; }))
7934
+ .subscribe(function (value) {
7935
+ // When leave component without object, use implicit value if :
7936
+ // - an explicit value
7937
+ // - field is not empty (user fill something)
7938
+ // - OR field empty but is required
7939
+ if (_this._implicitValue && ((_this.required && isNilOrBlank(value)) || (isNotNilOrBlank(value) && typeof value !== 'object'))) {
7940
+ _this.writeValue(_this._implicitValue);
7941
+ _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7942
+ _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7943
+ _this.checkIfTouched();
7944
+ _this.$filteredItems.next([_this._implicitValue]);
7945
+ }
7946
+ else if (isNilOrBlank(value)) {
7947
+ _this.writeValue(null);
7948
+ _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7949
+ _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7950
+ _this.checkIfTouched();
7951
+ _this.$filteredItems.next(undefined);
7952
+ }
7953
+ _this._implicitValue = null; // reset the implicit value
7954
+ }));
7955
+ // Listen form control status change
7956
+ this._subscription.add(this.formControl.statusChanges
7957
+ .pipe(
7958
+ //filter(() => this.enabled),
7959
+ operators.distinctUntilChanged())
7960
+ // Update component state
7961
+ .subscribe(function () { return _this.checkIfTouched(); }));
7962
+ this._subscription.add(this.keydownEscape.subscribe(function (event) {
7963
+ if (_this.isOpen) {
7964
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
7965
+ event === null || event === void 0 ? void 0 : event.preventDefault();
7966
+ // DEBUG
7967
+ //console.debug(this.logPrefix + " Closing the panel (keydown.escape)");
7968
+ _this.closePanel();
7969
+ }
7970
+ }));
7836
7971
  };
7837
7972
  MatChipsField.prototype.ngOnDestroy = function () {
7838
7973
  this._subscription.unsubscribe();
7974
+ if (this._itemsSubscription) {
7975
+ this._itemsSubscription.unsubscribe();
7976
+ }
7977
+ if (this._openedSubscription) {
7978
+ this._openedSubscription.unsubscribe();
7979
+ }
7839
7980
  this.$inputItems.complete();
7981
+ this.$inputItems.unsubscribe();
7982
+ this.$filteredItems.complete();
7983
+ this.$filteredItems.unsubscribe();
7984
+ this._reload$.complete();
7985
+ this._$filter.complete();
7986
+ this.dropButtonClick.complete();
7987
+ this.clicked.complete();
7988
+ this.blurred.complete();
7989
+ this.focused.complete();
7990
+ this.keydownEscape.complete();
7991
+ this.keyupEnter.complete();
7992
+ this._fetchMore$.complete();
7993
+ this._implicitValue = undefined;
7994
+ this.formControl = null;
7995
+ this.displayWith = null;
7996
+ this.equals = null;
7997
+ this.suggestFn = null;
7998
+ this.$filteredItems = null;
7999
+ this.config = null;
8000
+ this.classList = null;
8001
+ this._onChangeCallback = null;
8002
+ this._onTouchedCallback = null;
8003
+ this._onFetchMoreCallback = null;
8004
+ // Destroy the 'autocomplete' instance, to avoid memory leak
8005
+ if (this.autocomplete) {
8006
+ this.autocomplete.ngOnDestroy();
8007
+ }
7840
8008
  };
7841
8009
  /**
7842
8010
  * Add item to chips
@@ -7857,27 +8025,35 @@
7857
8025
  * @param item
7858
8026
  */
7859
8027
  MatChipsField.prototype.remove = function (item) {
7860
- var index = this.value && this.value.indexOf(item);
7861
- if (index >= 0) {
7862
- var value = this.value.slice();
7863
- value.splice(index, 1);
7864
- this.writeValue(value);
7865
- this.inputControl.setValue('');
8028
+ var value = this.value;
8029
+ var index = value ? value.indexOf(item) : -1;
8030
+ if (index !== -1) {
8031
+ var newValue = value.slice();
8032
+ newValue.splice(index, 1);
8033
+ this.writeValue(newValue);
8034
+ this.closePanel();
7866
8035
  }
7867
8036
  };
7868
8037
  /**
7869
8038
  * Allow to reload content. Useful when filter has been changed but not detected
7870
8039
  */
7871
- MatChipsField.prototype.reloadItems = function () {
7872
- this.onDropButtonClick.emit();
8040
+ MatChipsField.prototype.reloadItems = function (value) {
8041
+ // Force a refresh
8042
+ this._reload$.next(value || '*');
7873
8043
  };
7874
8044
  MatChipsField.prototype.writeValue = function (value) {
7875
- if (this.debug)
7876
- console.debug(this.logPrefix + ' Writing value: ', value);
8045
+ if (value && !Array.isArray(value)) {
8046
+ value = [value];
8047
+ }
7877
8048
  if (value !== this.formControl.value) {
8049
+ if (this.debug)
8050
+ console.debug(this.logPrefix + ' Writing value: ', value);
7878
8051
  this.formControl.patchValue(value, { emitEvent: false });
7879
8052
  this._onChangeCallback(value);
7880
8053
  }
8054
+ else {
8055
+ this.markForCheck();
8056
+ }
7881
8057
  };
7882
8058
  MatChipsField.prototype.registerOnChange = function (fn) {
7883
8059
  this._onChangeCallback = fn;
@@ -7886,6 +8062,10 @@
7886
8062
  this._onTouchedCallback = fn;
7887
8063
  };
7888
8064
  MatChipsField.prototype.setDisabledState = function (isDisabled) {
8065
+ var _a;
8066
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
8067
+ this.closePanel();
8068
+ }
7889
8069
  this.cd.markForCheck();
7890
8070
  };
7891
8071
  MatChipsField.prototype.focus = function () {
@@ -7905,6 +8085,7 @@
7905
8085
  return false;
7906
8086
  }
7907
8087
  var hasContent = selectInputContent(event);
8088
+ // If combo is empty, or if has content but should force to show panel on focus
7908
8089
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
7909
8090
  if (this.debug)
7910
8091
  console.debug(this.logPrefix + ' Emit focus event');
@@ -7913,22 +8094,85 @@
7913
8094
  }
7914
8095
  return false;
7915
8096
  };
8097
+ MatChipsField.prototype.filterInputTextBlurEvent = function (event) {
8098
+ if (!event || event.defaultPrevented)
8099
+ return;
8100
+ // Ignore event from mat-option
8101
+ if (event.relatedTarget instanceof HTMLElement && event.relatedTarget.tagName === 'MAT-OPTION') {
8102
+ event.preventDefault();
8103
+ if (event.stopPropagation)
8104
+ event.stopPropagation();
8105
+ event.returnValue = false;
8106
+ //DEBUG console.debug(this.logPrefix + " Cancelling blur event");
8107
+ return false;
8108
+ }
8109
+ //DEBUG
8110
+ //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
8111
+ // Move caret to the beginning (fix issue IMAGINE-469)
8112
+ selectInputRange(event.target, 0, 0);
8113
+ this.blurred.emit(event);
8114
+ return true;
8115
+ };
8116
+ MatChipsField.prototype.filterChipsFocusEvent = function (event) {
8117
+ // DEBUG
8118
+ if (this.debug)
8119
+ console.debug(this.logPrefix + ' Focus in chips list', event);
8120
+ // Ignore event in button
8121
+ this.matInputText.nativeElement.focus();
8122
+ };
7916
8123
  MatChipsField.prototype.clearValue = function (event) {
7917
8124
  this.writeValue(null);
7918
8125
  event.stopPropagation();
7919
8126
  };
8127
+ MatChipsField.prototype._initAutocompleteInfiniteScroll = function (threshold) {
8128
+ var _this = this;
8129
+ if (!this.autocomplete)
8130
+ return; // Skip
8131
+ // DEBUG
8132
+ //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
8133
+ if (this._openedSubscription) {
8134
+ this._openedSubscription.unsubscribe();
8135
+ this._subscription.remove(this._openedSubscription);
8136
+ }
8137
+ var opened$ = this.autocomplete._isOpen
8138
+ ? rxjs.timer(0)
8139
+ : this.autocomplete.opened.pipe(operators.debounceTime(200));
8140
+ var scrollEnd$ = opened$
8141
+ .pipe(operators.map(function (_) { return _this.getAutocompletePanel(); }), operators.filter(isNotNil), operators.switchMap(function (panel) { return fromScrollEndEvent(panel, threshold)
8142
+ .pipe(operators.takeUntil(_this.autocomplete.closed)); }));
8143
+ // Trigger fetch more, end end scroll reached
8144
+ this._openedSubscription = scrollEnd$
8145
+ .subscribe(function () { return _this._fetchMore$.emit(); });
8146
+ // Register subscription
8147
+ this._subscription.add(this._openedSubscription);
8148
+ };
8149
+ Object.defineProperty(MatChipsField.prototype, "isOpen", {
8150
+ get: function () {
8151
+ var _a;
8152
+ return ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) || false;
8153
+ },
8154
+ enumerable: false,
8155
+ configurable: true
8156
+ });
8157
+ MatChipsField.prototype.closePanel = function () {
8158
+ var _a, _b;
8159
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
8160
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
8161
+ return;
8162
+ }
8163
+ };
7920
8164
  /* -- private method -- */
7921
8165
  MatChipsField.prototype.suggest = function (value, filter) {
7922
8166
  return __awaiter(this, void 0, void 0, function () {
7923
- var res, data, total, filteredData;
8167
+ var res, data, total, fetchMore, filteredData, removedItemCount;
7924
8168
  var _this = this;
7925
- return __generator(this, function (_a) {
7926
- switch (_a.label) {
8169
+ return __generator(this, function (_c) {
8170
+ switch (_c.label) {
7927
8171
  case 0: return [4 /*yield*/, this.suggestFn(value, filter)];
7928
8172
  case 1:
7929
- res = _a.sent();
8173
+ res = _c.sent();
7930
8174
  // DEBUG
7931
- // console.debug(this.logPrefix + " Filtered items by suggestFn:", value, res);
8175
+ //console.debug(this.logPrefix + ' Filtered items by suggestFn:', value, res);
7932
8176
  if (!res) {
7933
8177
  this._itemCount = 0;
7934
8178
  res = [];
@@ -7938,13 +8182,16 @@
7938
8182
  this._itemCount = res.length || 0;
7939
8183
  }
7940
8184
  else {
7941
- data = res.data, total = res.total;
7942
- res = data;
8185
+ data = res.data, total = res.total, fetchMore = res.fetchMore;
7943
8186
  this._itemCount = toNumber(total, data && data.length || 0);
8187
+ this._onFetchMoreCallback = fetchMore;
8188
+ this._moreItemsCount = fetchMore && (this._itemCount - data.length) || 0;
8189
+ res = data;
7944
8190
  }
7945
- filteredData = (res || []).slice().filter(function (item1) { return _this.value.findIndex(function (item2) { return _this.compareWith(item1, item2); }) === -1; });
7946
- // Update items count
7947
- this._itemCount = this._itemCount - (((res === null || res === void 0 ? void 0 : res.length) || 0) - ((filteredData === null || filteredData === void 0 ? void 0 : filteredData.length) || 0));
8191
+ filteredData = (res || []).slice().filter(function (item1) { return _this.value.findIndex(function (item2) { return _this.equals(item1, item2); }) === -1; });
8192
+ removedItemCount = (((res === null || res === void 0 ? void 0 : res.length) || 0) - ((filteredData === null || filteredData === void 0 ? void 0 : filteredData.length) || 0));
8193
+ // Decrease the item count, with delta
8194
+ this._itemCount -= removedItemCount;
7948
8195
  if (this.debug)
7949
8196
  console.debug(this.logPrefix + ' Filtered items by suggestFn:', value, res);
7950
8197
  return [2 /*return*/, res];
@@ -7952,25 +8199,80 @@
7952
8199
  });
7953
8200
  });
7954
8201
  };
8202
+ MatChipsField.prototype.fetchMore = function () {
8203
+ return __awaiter(this, void 0, void 0, function () {
8204
+ var fetchMoreFn, _c, data, total, fetchMore;
8205
+ return __generator(this, function (_d) {
8206
+ switch (_d.label) {
8207
+ case 0:
8208
+ if (!this._onFetchMoreCallback)
8209
+ return [2 /*return*/, []];
8210
+ fetchMoreFn = this._onFetchMoreCallback;
8211
+ this._onFetchMoreCallback = undefined;
8212
+ return [4 /*yield*/, fetchMoreFn()];
8213
+ case 1:
8214
+ _c = _d.sent(), data = _c.data, total = _c.total, fetchMore = _c.fetchMore;
8215
+ this._itemCount = total || this._itemCount;
8216
+ this._onFetchMoreCallback = fetchMore;
8217
+ this._moreItemsCount = Math.max(0, this._moreItemsCount - data.length); // Borne min = 0
8218
+ return [2 /*return*/, data];
8219
+ }
8220
+ });
8221
+ });
8222
+ };
8223
+ MatChipsField.prototype.updateImplicitValue = function (items) {
8224
+ // Store implicit value (will use it onBlur if not other value selected)
8225
+ if (items && items.length === 1) {
8226
+ this._implicitValue = items[0];
8227
+ //this.formControl.setErrors(null);
8228
+ }
8229
+ else {
8230
+ this._implicitValue = undefined;
8231
+ }
8232
+ };
8233
+ MatChipsField.prototype.checkIfTouched = function () {
8234
+ if (this.formControl.touched) {
8235
+ this.cd.markForCheck();
8236
+ this._onTouchedCallback();
8237
+ }
8238
+ };
8239
+ MatChipsField.prototype.getAutocompletePanel = function () {
8240
+ var _a, _b;
8241
+ var ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
8242
+ if (!ele) {
8243
+ // DEBUG
8244
+ console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
8245
+ }
8246
+ return ele;
8247
+ };
7955
8248
  MatChipsField.prototype.markForCheck = function () {
7956
8249
  this.cd.markForCheck();
7957
8250
  };
8251
+ MatChipsField.prototype.markAsLoading = function () {
8252
+ if (this.$filteredItems.value) {
8253
+ this.$filteredItems.next(undefined);
8254
+ this._itemCount = undefined;
8255
+ this._implicitValue = undefined;
8256
+ this._onFetchMoreCallback = undefined;
8257
+ this._moreItemsCount = 0;
8258
+ this.markForCheck();
8259
+ }
8260
+ };
7958
8261
  return MatChipsField;
7959
8262
  }());
7960
8263
  MatChipsField.decorators = [
7961
8264
  { type: i0.Component, args: [{
7962
8265
  // eslint-disable-next-line @angular-eslint/component-selector
7963
8266
  selector: 'mat-chips-field',
7964
- 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",
7965
- providers: [
7966
- {
8267
+ 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\n (focus)=\"filterChipsFocusEvent($event)\" >\n <mat-chip\n *ngFor=\"let item of value\"\n [selectable]=\"false\"\n [removable]=\"!disabled\"\n (removed)=\"remove(item)\"\n [color]=\"chipColor\"\n >\n {{displayWith(item)}}\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\n </mat-chip>\n\n <input #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 <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 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 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",
8268
+ providers: [{
7967
8269
  provide: i1.NG_VALUE_ACCESSOR,
7968
8270
  multi: true,
7969
8271
  useExisting: i0.forwardRef(function () { return MatChipsField; })
7970
- }
7971
- ],
8272
+ }],
8273
+ encapsulation: i0.ViewEncapsulation.None,
7972
8274
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
7973
- styles: [":host{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%}"]
8275
+ styles: [":host{width:100%;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%}.mat-form-field-suffix{position:absolute!important;right:0!important;top:calc(100% - 50px)!important}.mat-chip.mat-standard-chip.mat-primary{background-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast)}.mat-chip.mat-standard-chip.mat-secondary{background-color:var(--ion-color-secondary);color:var(--ion-color-secondary-contrast)}.mat-chip.mat-standard-chip.mat-tertiary{background-color:var(--ion-color-tertiary);color:var(--ion-color-tertiary-contrast)}.mat-chip.mat-standard-chip.mat-accent{background-color:var(--ion-color-accent);color:var(--ion-color-accent-contrast)}.mat-chip.mat-standard-chip.mat-warning{background-color:var(--ion-color-warning);color:var(--ion-color-warning-contrast)}"]
7974
8276
  },] }
7975
8277
  ];
7976
8278
  MatChipsField.ctorParameters = function () { return [
@@ -7978,7 +8280,7 @@
7978
8280
  { type: i1.FormGroupDirective, decorators: [{ type: i0.Optional }] }
7979
8281
  ]; };
7980
8282
  MatChipsField.propDecorators = {
7981
- compareWith: [{ type: i0.Input }],
8283
+ equals: [{ type: i0.Input }],
7982
8284
  logPrefix: [{ type: i0.Input }],
7983
8285
  formControl: [{ type: i0.Input }],
7984
8286
  formControlName: [{ type: i0.Input }],
@@ -7997,16 +8299,27 @@
7997
8299
  highlightAccent: [{ type: i0.Input }],
7998
8300
  showAllOnFocus: [{ type: i0.Input }],
7999
8301
  showPanelOnFocus: [{ type: i0.Input }],
8000
- appAutofocus: [{ type: i0.Input }],
8302
+ autofocus: [{ type: i0.Input }],
8001
8303
  config: [{ type: i0.Input }],
8002
8304
  i18nPrefix: [{ type: i0.Input }],
8003
8305
  noResultMessage: [{ type: i0.Input }],
8004
- class: [{ type: i0.Input }],
8306
+ classList: [{ type: i0.Input, args: ['class',] }],
8307
+ panelWidth: [{ type: i0.Input }],
8308
+ matAutocompletePosition: [{ type: i0.Input }],
8309
+ itemSize: [{ type: i0.Input }],
8310
+ fetchMoreThreshold: [{ type: i0.Input }],
8311
+ suggestLengthThreshold: [{ type: i0.Input }],
8312
+ showLoadingSpinner: [{ type: i0.Input }],
8313
+ chipColor: [{ type: i0.Input }],
8005
8314
  debug: [{ type: i0.Input }],
8006
8315
  clicked: [{ type: i0.Output }],
8007
8316
  blurred: [{ type: i0.Output }],
8008
8317
  focused: [{ type: i0.Output }],
8318
+ dropButtonClick: [{ type: i0.Output }],
8319
+ keydownEscape: [{ type: i0.Output, args: ['keydown.escape',] }],
8320
+ keyupEnter: [{ type: i0.Output, args: ['keyup.enter',] }],
8009
8321
  matInputText: [{ type: i0.ViewChild, args: ['matInputText',] }],
8322
+ autocomplete: [{ type: i0.ViewChild, args: [autocomplete.MatAutocomplete,] }],
8010
8323
  autocompleteTrigger: [{ type: i0.ViewChild, args: [autocomplete.MatAutocompleteTrigger,] }],
8011
8324
  filter: [{ type: i0.Input }],
8012
8325
  tabindex: [{ type: i0.Input }],
@@ -18673,7 +18986,7 @@
18673
18986
  function AutocompleteTestPage(formBuilder) {
18674
18987
  this.formBuilder = formBuilder;
18675
18988
  this._items = deepCopy$1(FAKE_ENTITIES$1, 100);
18676
- this.$items = new rxjs.BehaviorSubject(undefined);
18989
+ this._$items = new rxjs.BehaviorSubject(undefined);
18677
18990
  this.autocompleteFields = new MatAutocompleteConfigHolder();
18678
18991
  this.memoryHide = false;
18679
18992
  this.memoryMobile = true;
@@ -18703,7 +19016,7 @@
18703
19016
  });
18704
19017
  // From $items observable
18705
19018
  this.autocompleteFields.add('entity-$items', {
18706
- items: this.$items,
19019
+ items: this._$items,
18707
19020
  attributes: ['label', 'name'],
18708
19021
  displayWith: this.entityToString
18709
19022
  });
@@ -18747,7 +19060,7 @@
18747
19060
  AutocompleteTestPage.prototype.loadItems = function () {
18748
19061
  return __awaiter(this, void 0, void 0, function () {
18749
19062
  return __generator(this, function (_a) {
18750
- this.$items.next(this._items.slice());
19063
+ this._$items.next(this._items.slice());
18751
19064
  return [2 /*return*/];
18752
19065
  });
18753
19066
  });
@@ -18788,7 +19101,7 @@
18788
19101
  AutocompleteTestPage.prototype.doSubmit = function (event) {
18789
19102
  console.debug('Validate form: ', this.form.value);
18790
19103
  };
18791
- AutocompleteTestPage.prototype.compareWithFn = function (o1, o2) {
19104
+ AutocompleteTestPage.prototype.equals = function (o1, o2) {
18792
19105
  return o1 && o2 && o1.id === o2.id;
18793
19106
  };
18794
19107
  AutocompleteTestPage.prototype.toggleMode = function (value) {
@@ -18821,7 +19134,7 @@
18821
19134
  AutocompleteTestPage.decorators = [
18822
19135
  { type: i0.Component, args: [{
18823
19136
  selector: 'app-autocomplete-test',
18824
- 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"
19137
+ 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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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;</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]=\"equals\"\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 search with a suggestLengthThreshold\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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 [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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]=\"equals\"\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"
18825
19138
  },] }
18826
19139
  ];
18827
19140
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -18992,7 +19305,7 @@
18992
19305
  SwipeTestPage.decorators = [
18993
19306
  { type: i0.Component, args: [{
18994
19307
  selector: 'app-swipe-test',
18995
- 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"
19308
+ 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"
18996
19309
  },] }
18997
19310
  ];
18998
19311
  SwipeTestPage.ctorParameters = function () { return [
@@ -19109,15 +19422,30 @@
19109
19422
  var FAKE_ENTITIES = [
19110
19423
  { id: 1, label: 'AAA', name: 'Item A' },
19111
19424
  { id: 2, label: 'BBB', name: 'Item B' },
19112
- { id: 3, label: 'CCC', name: 'Item C' }
19425
+ { id: 3, label: 'CCC', name: 'Item C' },
19426
+ { id: 4, label: 'DDD', name: 'Item D' },
19427
+ { id: 5, label: 'EEE', name: 'Item E' },
19428
+ { id: 6, label: 'FFF', name: 'Item F' },
19429
+ { id: 7, label: 'GGG', name: 'Item G' }
19113
19430
  ];
19114
- function deepCopy(values) {
19115
- return (values || FAKE_ENTITIES).map(function (entity) { return Object.assign({}, entity); });
19431
+ function deepCopy(values, size) {
19432
+ if (isNil(size)) {
19433
+ return (values || FAKE_ENTITIES).map(function (entity) { return Object.assign({}, entity); });
19434
+ }
19435
+ var result = [];
19436
+ var i = 1;
19437
+ while (result.length < size) {
19438
+ result = result.concat((values || FAKE_ENTITIES).map(function (entity) {
19439
+ var name = entity.name + ' #' + i;
19440
+ return Object.assign(Object.assign({}, entity), { id: i++, name: name });
19441
+ }));
19442
+ }
19443
+ return result.slice(0, size);
19116
19444
  }
19117
19445
  var ChipsTestPage = /** @class */ (function () {
19118
19446
  function ChipsTestPage(formBuilder) {
19119
19447
  this.formBuilder = formBuilder;
19120
- this._items = deepCopy(FAKE_ENTITIES);
19448
+ this._items = deepCopy(FAKE_ENTITIES, 100);
19121
19449
  this._$items = new rxjs.BehaviorSubject(undefined);
19122
19450
  this.autocompleteFields = new MatAutocompleteConfigHolder();
19123
19451
  this.form = formBuilder.group({
@@ -19133,15 +19461,17 @@
19133
19461
  this.autocompleteFields.add('entity-suggestFn', {
19134
19462
  suggestFn: function (value, filter) { return _this.suggest(value, filter); },
19135
19463
  attributes: ['label', 'name'],
19136
- displayWith: this.entityToString
19464
+ displayWith: this.entityToString,
19465
+ equals: function (o1, o2) { return EntityUtils.compare(o1, o2, 1, 'id') === 0; }
19137
19466
  });
19138
19467
  // From items
19139
19468
  this.autocompleteFields.add('entity-items', {
19140
- items: FAKE_ENTITIES.slice(),
19469
+ items: this._items.slice(),
19141
19470
  attributes: ['label', 'name'],
19142
- displayWith: this.entityToString
19471
+ displayWith: this.entityToString,
19472
+ equals: function (o1, o2) { return EntityUtils.compare(o1, o2, 1, 'id') === 0; }
19143
19473
  });
19144
- // From items
19474
+ // From $items observable
19145
19475
  this.autocompleteFields.add('entity-$items', {
19146
19476
  items: this._$items,
19147
19477
  attributes: ['label', 'name'],
@@ -19155,15 +19485,18 @@
19155
19485
  // Load the form with data
19156
19486
  ChipsTestPage.prototype.loadData = function () {
19157
19487
  return __awaiter(this, void 0, void 0, function () {
19158
- var data;
19488
+ var items, data;
19489
+ var _this = this;
19159
19490
  return __generator(this, function (_a) {
19491
+ items = deepCopy(FAKE_ENTITIES);
19160
19492
  data = {
19161
- entity: [],
19162
- // THis item is NOT in the items list => i should be displayed anyway
19163
- entityInitial: FAKE_ENTITIES.slice(1, 2),
19164
- disableEntity: FAKE_ENTITIES.slice(1, 2)
19493
+ entity: items.slice(0, 1),
19494
+ entityInitial: items.slice(1, 2),
19495
+ disableEntity: items.slice(1, 2)
19165
19496
  };
19166
19497
  this.form.setValue(data);
19498
+ // Load observables
19499
+ setTimeout(function () { return _this.loadItems(); }, 1000);
19167
19500
  return [2 /*return*/];
19168
19501
  });
19169
19502
  });
@@ -19171,7 +19504,7 @@
19171
19504
  ChipsTestPage.prototype.loadItems = function () {
19172
19505
  return __awaiter(this, void 0, void 0, function () {
19173
19506
  return __generator(this, function (_a) {
19174
- this._$items.next(deepCopy(FAKE_ENTITIES));
19507
+ this._$items.next(this._items.slice());
19175
19508
  return [2 /*return*/];
19176
19509
  });
19177
19510
  });
@@ -19181,15 +19514,38 @@
19181
19514
  };
19182
19515
  ChipsTestPage.prototype.suggest = function (value, filter) {
19183
19516
  return __awaiter(this, void 0, void 0, function () {
19517
+ var res, total, nextOffset;
19518
+ var _this = this;
19184
19519
  return __generator(this, function (_a) {
19185
- return [2 /*return*/, suggestFromArray(this._items, value, Object.assign(Object.assign({}, filter), { searchAttributes: ['label', 'name'] }))];
19520
+ filter = Object.assign({ offset: 0, size: 30 }, filter);
19521
+ res = suggestFromArray(this._items, value, Object.assign(Object.assign({}, filter), { searchAttributes: ['label', 'name'] }));
19522
+ total = res.total || res.data.length;
19523
+ nextOffset = filter.offset + res.data.length;
19524
+ if (nextOffset < total) {
19525
+ filter = Object.assign(Object.assign({}, filter), { offset: nextOffset });
19526
+ return [2 /*return*/, {
19527
+ total: total,
19528
+ data: res.data,
19529
+ fetchMore: function (variables) { return __awaiter(_this, void 0, void 0, function () {
19530
+ return __generator(this, function (_a) {
19531
+ switch (_a.label) {
19532
+ case 0: return [4 /*yield*/, sleep(1000)];
19533
+ case 1:
19534
+ _a.sent();
19535
+ return [2 /*return*/, this.suggest(value, Object.assign(Object.assign({}, filter), variables))];
19536
+ }
19537
+ });
19538
+ }); }
19539
+ }];
19540
+ }
19541
+ return [2 /*return*/, res];
19186
19542
  });
19187
19543
  });
19188
19544
  };
19189
19545
  ChipsTestPage.prototype.doSubmit = function (event) {
19190
19546
  console.debug('Validate form: ', this.form.value);
19191
19547
  };
19192
- ChipsTestPage.prototype.compareWithFn = function (o1, o2) {
19548
+ ChipsTestPage.prototype.equals = function (o1, o2) {
19193
19549
  return o1 && o2 && o1.id === o2.id;
19194
19550
  };
19195
19551
  /* -- protected methods -- */
@@ -19201,7 +19557,7 @@
19201
19557
  ChipsTestPage.decorators = [
19202
19558
  { type: i0.Component, args: [{
19203
19559
  selector: 'app-chips-test',
19204
- 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"
19560
+ 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 chipColor=\"accent\"\n [debug]=\"false\"\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 [logPrefix]=\"'[mat-chips-initialized] '\"\n chipColor=\"primary\"\n [debug]=\"true\"\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]=\"equals\"\n [logPrefix]=\"'[mat-chips-disabled] '\"\n chipColor=\"warning\"\n [debug]=\"true\"\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]=\"equals\"\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"
19205
19561
  },] }
19206
19562
  ];
19207
19563
  ChipsTestPage.ctorParameters = function () { return [
@@ -19835,12 +20191,23 @@
19835
20191
  };
19836
20192
 
19837
20193
  var AuthModal = /** @class */ (function () {
19838
- function AuthModal(accountService, viewCtrl, changeDetectorRef) {
20194
+ function AuthModal(accountService, viewCtrl, cd) {
19839
20195
  this.accountService = accountService;
19840
20196
  this.viewCtrl = viewCtrl;
19841
- this.changeDetectorRef = changeDetectorRef;
19842
- this.loading = false;
20197
+ this.cd = cd;
19843
20198
  }
20199
+ Object.defineProperty(AuthModal.prototype, "loading", {
20200
+ get: function () {
20201
+ var _a;
20202
+ return (_a = this.form) === null || _a === void 0 ? void 0 : _a.loading;
20203
+ },
20204
+ enumerable: false,
20205
+ configurable: true
20206
+ });
20207
+ AuthModal.prototype.ngOnInit = function () {
20208
+ this.form.markAsReady({ emitEvent: false });
20209
+ this.form.markAsLoaded();
20210
+ };
19844
20211
  AuthModal.prototype.cancel = function () {
19845
20212
  this.viewCtrl.dismiss();
19846
20213
  };
@@ -19848,31 +20215,30 @@
19848
20215
  return __awaiter(this, void 0, void 0, function () {
19849
20216
  var data, account, err_1;
19850
20217
  var _this = this;
19851
- return __generator(this, function (_a) {
19852
- switch (_a.label) {
20218
+ return __generator(this, function (_b) {
20219
+ switch (_b.label) {
19853
20220
  case 0:
19854
20221
  if (this.form.disabled)
19855
20222
  return [2 /*return*/];
19856
20223
  if (!this.form.valid) {
19857
- this.form.markAsTouched();
20224
+ this.form.markAllAsTouched();
19858
20225
  return [2 /*return*/];
19859
20226
  }
19860
- this.loading = true;
19861
- _a.label = 1;
20227
+ this.markAsLoading();
20228
+ _b.label = 1;
19862
20229
  case 1:
19863
- _a.trys.push([1, 3, , 4]);
20230
+ _b.trys.push([1, 3, , 4]);
19864
20231
  data = this.form.value;
19865
20232
  // Disable the form
19866
20233
  this.form.disable();
19867
20234
  return [4 /*yield*/, this.accountService.login(data)];
19868
20235
  case 2:
19869
- account = _a.sent();
20236
+ account = _b.sent();
19870
20237
  return [2 /*return*/, this.viewCtrl.dismiss(account)];
19871
20238
  case 3:
19872
- err_1 = _a.sent();
19873
- this.loading = false;
20239
+ err_1 = _b.sent();
19874
20240
  this.form.error = err_1 && err_1.message || err_1;
19875
- this.markForCheck();
20241
+ this.markAsLoaded();
19876
20242
  // Enable the form
19877
20243
  this.form.enable();
19878
20244
  // Reset form error on next changes
@@ -19887,7 +20253,13 @@
19887
20253
  });
19888
20254
  };
19889
20255
  AuthModal.prototype.markForCheck = function () {
19890
- this.changeDetectorRef.markForCheck();
20256
+ this.cd.markForCheck();
20257
+ };
20258
+ AuthModal.prototype.markAsLoading = function (opts) {
20259
+ this.form.markAsLoading(opts);
20260
+ };
20261
+ AuthModal.prototype.markAsLoaded = function (opts) {
20262
+ this.form.markAsLoaded(opts);
19891
20263
  };
19892
20264
  return AuthModal;
19893
20265
  }());
@@ -24012,22 +24384,26 @@
24012
24384
  switch (_a.label) {
24013
24385
  case 0:
24014
24386
  if (!this._fetchMoreFn)
24015
- return [2 /*return*/];
24387
+ return [2 /*return*/, false]; // Avoid multiple call
24016
24388
  if (this._editingRowCount > 0) {
24017
24389
  console.warn('Cannot fetch more because still editing row');
24018
24390
  return [2 /*return*/];
24019
24391
  }
24392
+ // Fetch next page
24393
+ this._fetchMoreFn = null; // Avoid multiple call
24020
24394
  return [4 /*yield*/, this._fetchMoreFn()];
24021
24395
  case 1:
24022
24396
  res = _a.sent();
24397
+ // Skip if empty (no more data)
24023
24398
  if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
24024
- return [2 /*return*/];
24399
+ return [2 /*return*/, false];
24025
24400
  return [4 /*yield*/, this.getData()];
24026
24401
  case 2:
24027
24402
  existingData = _a.sent();
24028
24403
  _super.updateDatasource.call(this, existingData.concat.apply(existingData, __spread(res.data)), opts);
24404
+ // Remember fetchMore
24029
24405
  this._fetchMoreFn = res.fetchMore;
24030
- return [2 /*return*/];
24406
+ return [2 /*return*/, true];
24031
24407
  }
24032
24408
  });
24033
24409
  });
@@ -28923,7 +29299,6 @@
28923
29299
  exports.waitForTrue = waitForTrue;
28924
29300
  exports.waitIdle = waitIdle;
28925
29301
  exports.waitWhilePending = waitWhilePending;
28926
- exports["ɵ0"] = ɵ0$5;
28927
29302
  exports["ɵa"] = CustomReuseStrategy;
28928
29303
  exports["ɵb"] = MatNumpadDomService;
28929
29304
  exports["ɵc"] = SharedMatBadgeIconModule;