@sumaris-net/ngx-components 1.6.0 → 1.6.4

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 (25) hide show
  1. package/bundles/sumaris-net.ngx-components.umd.js +572 -218
  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 +8 -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 +35 -1
  8. package/esm2015/src/app/shared/form/field.model.js +1 -1
  9. package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +103 -102
  10. package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +2 -2
  11. package/esm2015/src/app/shared/material/chips/material.chips.js +354 -81
  12. package/esm2015/src/app/shared/material/chips/testing/chips.test.js +13 -6
  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 +521 -196
  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 +6 -1
  20. package/src/app/shared/form/field.model.d.ts +2 -1
  21. package/src/app/shared/material/autocomplete/material.autocomplete.d.ts +35 -35
  22. package/src/app/shared/material/chips/material.chips.d.ts +38 -10
  23. package/src/app/shared/material/chips/testing/chips.test.d.ts +1 -1
  24. package/src/app/shared/material/swipe/material.swipe.d.ts +2 -2
  25. package/sumaris-net.ngx-components.metadata.json +1 -1
@@ -1262,11 +1262,10 @@
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 compareWith = 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
- displayWith: displayWith,
1269
- compareWith: compareWith });
1268
+ displayWith: displayWith, equals: compareWith });
1270
1269
  this.fields[fieldName] = config;
1271
1270
  return config;
1272
1271
  };
@@ -1278,11 +1277,6 @@
1278
1277
  };
1279
1278
  return MatAutocompleteConfigHolder;
1280
1279
  }());
1281
- var DEFAULT_VALUE_ACCESSOR$6 = {
1282
- provide: i1.NG_VALUE_ACCESSOR,
1283
- useExisting: i0.forwardRef(function () { return MatAutocompleteField; }),
1284
- multi: true
1285
- };
1286
1280
  var noop$7 = function () { };
1287
1281
  var ɵ0$a = noop$7;
1288
1282
  var MatAutocompleteField = /** @class */ (function () {
@@ -1291,14 +1285,6 @@
1291
1285
  this.formGroupDir = formGroupDir;
1292
1286
  this._onChangeCallback = noop$7;
1293
1287
  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();
1302
1288
  this.logPrefix = '[mat-autocomplete] ';
1303
1289
  this.formControlName = null;
1304
1290
  this.required = false;
@@ -1311,13 +1297,21 @@
1311
1297
  this.fetchMoreThreshold = '15%';
1312
1298
  this.suggestLengthThreshold = null;
1313
1299
  this.showLoadingSpinner = true;
1300
+ this.clicked = new i0.EventEmitter();
1301
+ this.blurred = new i0.EventEmitter();
1302
+ this.focused = new i0.EventEmitter();
1303
+ this.dropButtonClick = new i0.EventEmitter(true);
1304
+ this.keydownEscape = new i0.EventEmitter();
1305
+ this.keyupEnter = new i0.EventEmitter();
1314
1306
  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();
1307
+ this._readonly = false;
1308
+ this.$inputItems = new rxjs.BehaviorSubject(undefined);
1309
+ this.$filteredItems = new rxjs.BehaviorSubject(undefined);
1310
+ this.displayValue = '';
1311
+ this._fetchMore$ = new i0.EventEmitter();
1312
+ this._subscription = new rxjs.Subscription();
1313
+ this._$filter = new rxjs.BehaviorSubject(undefined);
1314
+ this._reload$ = new rxjs.Subject();
1321
1315
  }
1322
1316
  Object.defineProperty(MatAutocompleteField.prototype, "itemCount", {
1323
1317
  get: function () {
@@ -1335,13 +1329,13 @@
1335
1329
  });
1336
1330
  Object.defineProperty(MatAutocompleteField.prototype, "filter", {
1337
1331
  get: function () {
1338
- return this._filter$.value;
1332
+ return this._$filter.value;
1339
1333
  },
1340
1334
  set: function (value) {
1341
- if (value !== this._filter$.value) {
1335
+ if (value !== this._$filter.value) {
1342
1336
  // DEBUG
1343
1337
  //console.debug(this.logPrefix + " Setting filter:", value);
1344
- this._filter$.next(value);
1338
+ this._$filter.next(value);
1345
1339
  }
1346
1340
  },
1347
1341
  enumerable: false,
@@ -1434,6 +1428,7 @@
1434
1428
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
1435
1429
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
1436
1430
  this.displayWith = this.displayWith || this.config.displayWith;
1431
+ this.equals = this.equals || this.config.equals;
1437
1432
  this.mobile = toBoolean(this.mobile, this.config.mobile);
1438
1433
  this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
1439
1434
  this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
@@ -1448,21 +1443,18 @@
1448
1443
  this.displayColumnSizes = this.displayColumnSizes
1449
1444
  // if only column: auto size
1450
1445
  || (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
- });
1446
+ // Computed column size:
1447
+ // - if label then col size = 2
1448
+ // - if rankOrder then col size = 1
1449
+ // - ese => auto size
1450
+ || this.displayAttributes.map(function (attr) { return (attr && attr.endsWith('label')) ? 2
1451
+ : ((attr && attr.endsWith('rankOrder')) ? 1
1452
+ : undefined); });
1459
1453
  this.displayColumnNames = this.displayAttributes.map(function (attr, index) { return _this.displayColumnNames && _this.displayColumnNames[index] ||
1460
1454
  (_this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()); });
1461
1455
  this.mobile = toBoolean(this.mobile, false);
1462
1456
  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; };
1457
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
1466
1458
  var classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
1467
1459
  this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
1468
1460
  || (classList.includes('min-width-large') && '400px')
@@ -1478,7 +1470,7 @@
1478
1470
  var suggestFromArrayFn_1 = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
1479
1471
  return __generator(this, function (_e) {
1480
1472
  // DEBUG
1481
- //console.debug(this.logPrefix + " Calling suggestFromArray with value=", value);
1473
+ //console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
1482
1474
  return [2 /*return*/, suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter))];
1483
1475
  });
1484
1476
  }); };
@@ -1505,10 +1497,18 @@
1505
1497
  }
1506
1498
  else if (!this.searchable) {
1507
1499
  // 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)
1500
+ 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
1501
  operators.switchMap(function (filter) { return _this.suggest('*', filter); }))
1510
1502
  .subscribe(function (items) { return _this.$inputItems.next(items); }));
1511
1503
  }
1504
+ // Send value to suggest when :
1505
+ // - is nil and '*', and no min length threshold
1506
+ // - is not nil and not a string type (e.g. object)
1507
+ // - is not nil and is a string, and has enough character
1508
+ var thresholdFilterFn = function (value) { return (isNilOrBlank(value) || (value === '*')
1509
+ ? (_this.suggestLengthThreshold <= 0)
1510
+ : (!(typeof value === 'string')
1511
+ || value.length >= _this.suggestLengthThreshold)); };
1512
1512
  var filteredItemsChanges = rxjs.merge(
1513
1513
  // Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
1514
1514
  this._reload$,
@@ -1516,11 +1516,7 @@
1516
1516
  this.formControl.valueChanges
1517
1517
  .pipe(operators.filter(function (value) { return _this.enabled && _this.searchable && isNotNilString(value); }),
1518
1518
  // 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
- }),
1519
+ operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
1524
1520
  // Filter if not enough character
1525
1521
  operators.filter(function (value) { return value.length >= _this.suggestLengthThreshold; }),
1526
1522
  // Wait a debounce time
@@ -1546,28 +1542,24 @@
1546
1542
  // DEBUG
1547
1543
  //tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
1548
1544
  ),
1545
+ // On dropdown button click (no distinctUntilChanged(), nor debounceTime)
1546
+ this.dropButtonClick
1547
+ .pipe(operators.filter(function (event) { return _this.searchable && _this.enabled && (!event || !event.defaultPrevented); }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; }),
1548
+ // Make enough characters
1549
+ operators.filter(thresholdFilterFn)),
1549
1550
  // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
1550
1551
  rxjs.merge(
1551
1552
  // 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; })))
1553
+ rxjs.merge(this.focused, this.clicked)
1554
+ .pipe(operators.filter(function (_) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; })), rxjs.merge(this.$inputItems, this._$filter)
1555
+ .pipe(operators.filter(function (_) { return _this.searchable && _this.enabled; }), operators.map(function (_) { return _this.formControl.value; })))
1558
1556
  .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)); }),
1557
+ // Make enough characters
1558
+ operators.filter(thresholdFilterFn),
1569
1559
  // Distinguish changes
1570
- operators.distinctUntilChanged()))
1560
+ operators.distinctUntilChanged(),
1561
+ // DEBUG
1562
+ operators.tap(function (value) { return console.debug(_this.logPrefix + ' Received update event: ', value); })))
1571
1563
  .pipe(
1572
1564
  // Suggest values
1573
1565
  operators.mergeMap(function (value) { return _this.suggest(value, _this.filter); }),
@@ -1593,7 +1585,7 @@
1593
1585
  // Make sure control value is inside (mat-select)
1594
1586
  if (items && !_this.searchable) {
1595
1587
  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) {
1588
+ if (isNotNil(value_1) && typeof value_1 === 'object' && items.findIndex(function (item) { return _this.equals(item, value_1); }) === -1) {
1597
1589
  // If form value is missing: add it to the list
1598
1590
  items = items.concat(value_1);
1599
1591
  }
@@ -1602,7 +1594,7 @@
1602
1594
  _this.$filteredItems.next(items);
1603
1595
  }));
1604
1596
  // Applying implicit value, on blur
1605
- this._subscription.add(this.onBlur
1597
+ this._subscription.add(this.blurred
1606
1598
  .pipe(
1607
1599
  // Skip if not searchable
1608
1600
  operators.filter(function (_) { return _this.searchable; }), operators.map(function (_) { return _this.formControl.value; }))
@@ -1616,12 +1608,14 @@
1616
1608
  _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
1617
1609
  _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
1618
1610
  _this.checkIfTouched();
1611
+ _this.$filteredItems.next([_this._implicitValue]);
1619
1612
  }
1620
1613
  else if (isNilOrBlank(value)) {
1621
1614
  _this.writeValue(null);
1622
1615
  _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
1623
1616
  _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
1624
1617
  _this.checkIfTouched();
1618
+ _this.$filteredItems.next(undefined);
1625
1619
  }
1626
1620
  _this._implicitValue = null; // reset the implicit value
1627
1621
  }));
@@ -1632,7 +1626,7 @@
1632
1626
  operators.distinctUntilChanged())
1633
1627
  // Update component state
1634
1628
  .subscribe(function () { return _this.checkIfTouched(); }));
1635
- this._subscription.add(this.onKeydownEscape.subscribe(function (event) {
1629
+ this._subscription.add(this.keydownEscape.subscribe(function (event) {
1636
1630
  if (_this.isOpen) {
1637
1631
  event === null || event === void 0 ? void 0 : event.stopPropagation();
1638
1632
  event === null || event === void 0 ? void 0 : event.preventDefault();
@@ -1651,20 +1645,22 @@
1651
1645
  this._openedSubscription.unsubscribe();
1652
1646
  }
1653
1647
  this.$inputItems.complete();
1648
+ this.$inputItems.unsubscribe();
1654
1649
  this.$filteredItems.complete();
1650
+ this.$filteredItems.unsubscribe();
1655
1651
  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();
1652
+ this._$filter.complete();
1653
+ this.dropButtonClick.complete();
1654
+ this.clicked.complete();
1655
+ this.blurred.complete();
1656
+ this.focused.complete();
1657
+ this.keydownEscape.complete();
1658
+ this.keyupEnter.complete();
1663
1659
  this._fetchMore$.complete();
1664
1660
  this._implicitValue = undefined;
1665
1661
  this.formControl = null;
1666
1662
  this.displayWith = null;
1667
- this.compareWith = null;
1663
+ this.equals = null;
1668
1664
  this.suggestFn = null;
1669
1665
  this.$filteredItems = null;
1670
1666
  this.matSelectItems$ = null;
@@ -1674,8 +1670,8 @@
1674
1670
  this._onTouchedCallback = null;
1675
1671
  this._onFetchMoreCallback = null;
1676
1672
  // Destroy the 'autocomplete' instance, to avoid memory leak
1677
- if (this.matAutocomplete) {
1678
- this.matAutocomplete.ngOnDestroy();
1673
+ if (this.autocomplete) {
1674
+ this.autocomplete.ngOnDestroy();
1679
1675
  }
1680
1676
  };
1681
1677
  /**
@@ -1701,7 +1697,7 @@
1701
1697
  };
1702
1698
  MatAutocompleteField.prototype.setDisabledState = function (isDisabled) {
1703
1699
  var _a;
1704
- if (isDisabled && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1700
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
1705
1701
  this.closePanel();
1706
1702
  }
1707
1703
  this.cd.markForCheck();
@@ -1715,7 +1711,7 @@
1715
1711
  (_a = this.matSelect) === null || _a === void 0 ? void 0 : _a.focus();
1716
1712
  }
1717
1713
  };
1718
- MatAutocompleteField.prototype.filterInputTextFocusInEvent = function (event) {
1714
+ MatAutocompleteField.prototype.filterInputTextFocusEvent = function (event) {
1719
1715
  if (!event || event.defaultPrevented)
1720
1716
  return;
1721
1717
  // Ignore event from mat-option
@@ -1724,7 +1720,7 @@
1724
1720
  if (event.stopPropagation)
1725
1721
  event.stopPropagation();
1726
1722
  event.returnValue = false;
1727
- //DEBUG console.debug(this.logPrefix + " Cancelling focus event");
1723
+ //DEBUG console.debug(this.logPrefix + ' Cancelling focus event');
1728
1724
  return false;
1729
1725
  }
1730
1726
  var hasContent = selectInputContent(event);
@@ -1732,7 +1728,7 @@
1732
1728
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
1733
1729
  // DEBUG
1734
1730
  //console.debug(this.logPrefix + ' Emit focus event');
1735
- this.onFocus.emit(event);
1731
+ this.focused.emit(event);
1736
1732
  return true;
1737
1733
  }
1738
1734
  return false;
@@ -1753,7 +1749,7 @@
1753
1749
  //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
1754
1750
  // Move caret to the beginning (fix issue IMAGINE-469)
1755
1751
  selectInputRange(event.target, 0, 0);
1756
- this.onBlur.emit(event);
1752
+ this.blurred.emit(event);
1757
1753
  return true;
1758
1754
  };
1759
1755
  MatAutocompleteField.prototype.filterMatSelectFocusEvent = function (event) {
@@ -1761,7 +1757,7 @@
1761
1757
  return;
1762
1758
  // DEBUG
1763
1759
  // console.debug(this.logPrefix + " Received <mat-select> focus event", event);
1764
- this.onFocus.emit(event);
1760
+ this.focused.emit(event);
1765
1761
  };
1766
1762
  MatAutocompleteField.prototype.filterMatSelectBlurEvent = function (event) {
1767
1763
  if (!event || event.defaultPrevented)
@@ -1778,7 +1774,7 @@
1778
1774
  // console.debug(this.logPrefix + " Cancelling <mat-select> blur event");
1779
1775
  return false;
1780
1776
  }
1781
- this.onBlur.emit(event);
1777
+ this.blurred.emit(event);
1782
1778
  return true;
1783
1779
  };
1784
1780
  MatAutocompleteField.prototype.toggleSearch = function (event) {
@@ -1801,7 +1797,7 @@
1801
1797
  };
1802
1798
  MatAutocompleteField.prototype._initAutocompleteInfiniteScroll = function (threshold) {
1803
1799
  var _this = this;
1804
- if (!this.matAutocomplete)
1800
+ if (!this.autocomplete)
1805
1801
  return; // Skip
1806
1802
  // DEBUG
1807
1803
  //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
@@ -1809,12 +1805,12 @@
1809
1805
  this._openedSubscription.unsubscribe();
1810
1806
  this._subscription.remove(this._openedSubscription);
1811
1807
  }
1812
- var opened$ = this.matAutocomplete._isOpen
1808
+ var opened$ = this.autocomplete._isOpen
1813
1809
  ? rxjs.timer(0)
1814
- : this.matAutocomplete.opened.pipe(operators.debounceTime(200));
1810
+ : this.autocomplete.opened.pipe(operators.debounceTime(200));
1815
1811
  var scrollEnd$ = opened$
1816
1812
  .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)); }));
1813
+ .pipe(operators.takeUntil(_this.autocomplete.closed)); }));
1818
1814
  // Trigger fetch more, end end scroll reached
1819
1815
  this._openedSubscription = scrollEnd$
1820
1816
  .subscribe(function () { return _this._fetchMore$.emit(); });
@@ -1847,7 +1843,7 @@
1847
1843
  Object.defineProperty(MatAutocompleteField.prototype, "isOpen", {
1848
1844
  get: function () {
1849
1845
  var _a, _b;
1850
- return (this.searchable && ((_a = this.matAutocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1846
+ return (this.searchable && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
1851
1847
  || ((_b = this.matSelect) === null || _b === void 0 ? void 0 : _b.panelOpen)
1852
1848
  || false;
1853
1849
  },
@@ -1856,8 +1852,8 @@
1856
1852
  });
1857
1853
  MatAutocompleteField.prototype.closePanel = function () {
1858
1854
  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();
1855
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
1856
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
1861
1857
  return;
1862
1858
  }
1863
1859
  if ((_c = this.matSelect) === null || _c === void 0 ? void 0 : _c.panelOpen) {
@@ -1938,7 +1934,7 @@
1938
1934
  };
1939
1935
  MatAutocompleteField.prototype.getAutocompletePanel = function () {
1940
1936
  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;
1937
+ 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
1938
  if (!ele) {
1943
1939
  // DEBUG
1944
1940
  console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
@@ -1973,10 +1969,14 @@
1973
1969
  { type: i0.Component, args: [{
1974
1970
  // eslint-disable-next-line @angular-eslint/component-selector
1975
1971
  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],
1972
+ 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 [class.cdk-visually-hidden]=\"!searchable\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1973
+ providers: [{
1974
+ provide: i1.NG_VALUE_ACCESSOR,
1975
+ multi: true,
1976
+ useExisting: i0.forwardRef(function () { return MatAutocompleteField; })
1977
+ }],
1978
1978
  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}"]
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%}"]
1980
1980
  },] }
1981
1981
  ];
1982
1982
  MatAutocompleteField.ctorParameters = function () { return [
@@ -1984,7 +1984,7 @@
1984
1984
  { type: i1.FormGroupDirective, decorators: [{ type: i0.Optional }] }
1985
1985
  ]; };
1986
1986
  MatAutocompleteField.propDecorators = {
1987
- compareWith: [{ type: i0.Input }],
1987
+ equals: [{ type: i0.Input }],
1988
1988
  logPrefix: [{ type: i0.Input }],
1989
1989
  formControl: [{ type: i0.Input }],
1990
1990
  formControlName: [{ type: i0.Input }],
@@ -2014,21 +2014,21 @@
2014
2014
  fetchMoreThreshold: [{ type: i0.Input }],
2015
2015
  suggestLengthThreshold: [{ type: i0.Input }],
2016
2016
  showLoadingSpinner: [{ type: i0.Input }],
2017
+ clicked: [{ type: i0.Output, args: ['click',] }],
2018
+ blurred: [{ type: i0.Output, args: ['blur',] }],
2019
+ focused: [{ type: i0.Output, args: ['focus',] }],
2020
+ dropButtonClick: [{ type: i0.Output }],
2021
+ keydownEscape: [{ type: i0.Output, args: ['keydown.escape',] }],
2022
+ keyupEnter: [{ type: i0.Output, args: ['keyup.enter',] }],
2023
+ matSelect: [{ type: i0.ViewChild, args: ['matSelect',] }],
2024
+ matInputText: [{ type: i0.ViewChild, args: ['matInputText',] }],
2025
+ autocomplete: [{ type: i0.ViewChild, args: [autocomplete.MatAutocomplete,] }],
2026
+ autocompleteTrigger: [{ type: i0.ViewChild, args: [autocomplete.MatAutocompleteTrigger,] }],
2017
2027
  animationsDisabled: [{ type: i0.HostBinding, args: ['@.disabled',] }],
2018
2028
  filter: [{ type: i0.Input }],
2019
2029
  readonly: [{ type: i0.Input }],
2020
2030
  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,] }]
2031
+ items: [{ type: i0.Input }]
2032
2032
  };
2033
2033
 
2034
2034
  var DateFormatPipe = /** @class */ (function () {
@@ -7347,7 +7347,7 @@
7347
7347
  // Default values
7348
7348
  this.displayAttributes = this.displayAttributes || ['label', 'name'];
7349
7349
  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; });
7350
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7351
7351
  this.mobile = toBoolean(this.mobile, false);
7352
7352
  };
7353
7353
  MatSwipeField.prototype.ngOnDestroy = function () {
@@ -7409,7 +7409,7 @@
7409
7409
  if (this._writing)
7410
7410
  return;
7411
7411
  this._writing = true;
7412
- if (!this.compareWithFn(value, this._value)) {
7412
+ if (!this.equals(value, this._value)) {
7413
7413
  this._value = value;
7414
7414
  this.showSlides = isNotNil(this._value);
7415
7415
  this.updateSlides();
@@ -7498,7 +7498,7 @@
7498
7498
  MatSwipeField.prototype.updateSlides = function () {
7499
7499
  var _this = this;
7500
7500
  if (this.showSlides) {
7501
- var itemIndex = (this.$items.getValue() || []).findIndex(function (value) { return _this.compareWithFn(value, _this._value); });
7501
+ var itemIndex = (this.$items.getValue() || []).findIndex(function (value) { return _this.equals(value, _this._value); });
7502
7502
  if (itemIndex >= 0) {
7503
7503
  this.slideTo(itemIndex);
7504
7504
  }
@@ -7585,7 +7585,7 @@
7585
7585
  required: [{ type: i0.Input }],
7586
7586
  mobile: [{ type: i0.Input }],
7587
7587
  clearable: [{ type: i0.Input }],
7588
- compareWithFn: [{ type: i0.Input }],
7588
+ equals: [{ type: i0.Input }],
7589
7589
  displayWith: [{ type: i0.Input }],
7590
7590
  displayAttributes: [{ type: i0.Input }],
7591
7591
  appAutofocus: [{ type: i0.Input }],
@@ -7634,23 +7634,32 @@
7634
7634
  this._onChangeCallback = function (_) { };
7635
7635
  this._onTouchedCallback = function () { };
7636
7636
  this.logPrefix = '[mat-chips] ';
7637
+ this.formControlName = null;
7637
7638
  this.required = false;
7638
7639
  this.readonly = false;
7639
7640
  this.clearable = false;
7640
- this.debounceTime = 250;
7641
- this.highlightAccent = false;
7641
+ this.debounceTime = null;
7642
7642
  this.i18nPrefix = 'REFERENTIAL.';
7643
7643
  this.noResultMessage = 'COMMON.NO_RESULT';
7644
7644
  this.debug = false;
7645
+ this.itemSize = '48px';
7646
+ this.fetchMoreThreshold = '15%';
7647
+ this.suggestLengthThreshold = null;
7648
+ this.showLoadingSpinner = true;
7649
+ this.chipColor = null;
7645
7650
  this.clicked = new i0.EventEmitter();
7646
7651
  this.blurred = new i0.EventEmitter();
7647
7652
  this.focused = new i0.EventEmitter();
7653
+ this.dropButtonClick = new i0.EventEmitter(true);
7654
+ this.keydownEscape = new i0.EventEmitter();
7655
+ this.keyupEnter = new i0.EventEmitter();
7648
7656
  this.$inputItems = new rxjs.BehaviorSubject(undefined);
7649
- this.onDropButtonClick = new i0.EventEmitter(true);
7657
+ this.$filteredItems = new rxjs.BehaviorSubject(undefined);
7650
7658
  this.inputControl = new i1.FormControl();
7651
- this.getPropertyByPath = getPropertyByPath;
7659
+ this._fetchMore$ = new i0.EventEmitter();
7652
7660
  this._subscription = new rxjs.Subscription();
7653
7661
  this._$filter = new rxjs.BehaviorSubject(undefined);
7662
+ this._reload$ = new rxjs.Subject();
7654
7663
  }
7655
7664
  Object.defineProperty(MatChipsField.prototype, "itemCount", {
7656
7665
  get: function () {
@@ -7659,14 +7668,21 @@
7659
7668
  enumerable: false,
7660
7669
  configurable: true
7661
7670
  });
7671
+ Object.defineProperty(MatChipsField.prototype, "canFetchMore", {
7672
+ get: function () {
7673
+ return this._onFetchMoreCallback && this._moreItemsCount > 0;
7674
+ },
7675
+ enumerable: false,
7676
+ configurable: true
7677
+ });
7662
7678
  Object.defineProperty(MatChipsField.prototype, "filter", {
7663
7679
  get: function () {
7664
- return this._$filter.getValue();
7680
+ return this._$filter.value;
7665
7681
  },
7666
7682
  set: function (value) {
7667
- if (this.debug)
7668
- console.debug(this.logPrefix + ' Setting filter:', value);
7669
- if (value !== this._$filter.getValue()) {
7683
+ if (value !== this._$filter.value) {
7684
+ // DEBUG
7685
+ //console.debug(this.logPrefix + " Setting filter:", value);
7670
7686
  this._$filter.next(value);
7671
7687
  }
7672
7688
  },
@@ -7685,19 +7701,25 @@
7685
7701
  configurable: true
7686
7702
  });
7687
7703
  Object.defineProperty(MatChipsField.prototype, "items", {
7704
+ get: function () {
7705
+ return this.$inputItems;
7706
+ },
7688
7707
  set: function (value) {
7689
7708
  var _this = this;
7690
7709
  // Remove previous subscription on items, (if exits)
7691
7710
  if (this._itemsSubscription) {
7692
- console.warn('Items received twice !');
7711
+ console.warn(this.logPrefix + ' Items received twice !');
7693
7712
  this._subscription.remove(this._itemsSubscription);
7694
7713
  this._itemsSubscription.unsubscribe();
7695
7714
  }
7696
7715
  if (rxjs.isObservable(value)) {
7697
- this._itemsSubscription = this._subscription.add(value.subscribe(function (v) { return _this.$inputItems.next(v); }));
7716
+ this._itemsSubscription = this._subscription.add(value.subscribe(function (v) {
7717
+ //console.warn(this.logPrefix + " Received items: ", v);
7718
+ _this.$inputItems.next(v);
7719
+ }));
7698
7720
  }
7699
7721
  else {
7700
- if (value !== this.$inputItems.getValue()) {
7722
+ if (value !== this.$inputItems.value) {
7701
7723
  this.$inputItems.next(value);
7702
7724
  }
7703
7725
  }
@@ -7728,6 +7750,7 @@
7728
7750
  });
7729
7751
  MatChipsField.prototype.ngOnInit = function () {
7730
7752
  var _this = this;
7753
+ var _a, _b;
7731
7754
  this.formControl = this.formControl || this.formControlName && this.formGroupDir && this.formGroupDir.form.get(this.formControlName);
7732
7755
  if (!this.formControl)
7733
7756
  throw new Error('Missing mandatory attribute \'formControl\' or \'formControlName\' in <mat-chips-field>.');
@@ -7742,101 +7765,222 @@
7742
7765
  this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
7743
7766
  this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
7744
7767
  this.displayWith = this.displayWith || this.config.displayWith;
7745
- this.compareWith = this.compareWith || this.config.compareWith;
7768
+ this.equals = this.equals || this.config.equals;
7746
7769
  this.mobile = toBoolean(this.mobile, this.config.mobile);
7747
- this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, true));
7770
+ this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
7771
+ this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
7748
7772
  this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus, true));
7749
- this.class = this.class || this.config.class;
7773
+ this.classList = this.classList || this.config.class;
7774
+ this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
7775
+ this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
7750
7776
  }
7751
7777
  // Default values
7752
- this.displayAttributes = this.displayAttributes || (this.filter && this.filter.attributes) || ['label', 'name'];
7778
+ this.displayAttributes = this.displayAttributes || ((_a = this.filter) === null || _a === void 0 ? void 0 : _a.attributes) || ['label', 'name'];
7753
7779
  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); });
7780
+ this.displayColumnSizes = this.displayColumnSizes
7781
+ // if only column: auto size
7782
+ || (this.displayAttributes.length === 1 && [undefined])
7783
+ // Computed column size:
7784
+ // - if label then col size = 2
7785
+ // - if rankOrder then col size = 1
7786
+ // - ese => auto size
7787
+ || this.displayAttributes.map(function (attr) { return (attr && attr.endsWith('label')) ? 2
7788
+ : ((attr && attr.endsWith('rankOrder')) ? 1
7789
+ : undefined); });
7762
7790
  this.displayColumnNames = this.displayAttributes.map(function (attr, index) { return _this.displayColumnNames && _this.displayColumnNames[index] ||
7763
7791
  (_this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()); });
7764
7792
  this.mobile = toBoolean(this.mobile, false);
7793
+ this.equals = this.equals || (function (o1, o2) { return o1 && o2 && o1.id === o2.id; });
7794
+ var classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
7795
+ this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
7796
+ || (classList.includes('min-width-large') && '400px')
7797
+ || (classList.includes('min-width-xlarge') && '450px')
7798
+ || (classList.includes('mat-autocomplete-panel-full-size') && '100vw')));
7799
+ this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, true);
7800
+ this.debounceTime = toNumber(this.debounceTime, 250);
7801
+ this.highlightAccent = toBoolean(this.highlightAccent, false);
7802
+ this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
7803
+ this.matAutocompletePosition = this.matAutocompletePosition || (this.mobile ? 'above' : 'auto'); // On mobile, set position to above (because of bottom keyboard)
7765
7804
  // No suggestFn: filter on the given items
7766
7805
  if (!this.suggestFn) {
7767
7806
  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
- }
7807
+ return __generator(this, function (_c) {
7808
+ if (this.debug)
7809
+ console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
7810
+ return [2 /*return*/, suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter))];
7780
7811
  });
7781
7812
  }); };
7782
7813
  // Wait (once) that items are loaded, then call suggest from array fn
7783
7814
  this.suggestFn = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
7784
- return __generator(this, function (_a) {
7785
- switch (_a.label) {
7815
+ return __generator(this, function (_c) {
7816
+ switch (_c.label) {
7786
7817
  case 0:
7787
- if (!isNil(this.$inputItems.getValue())) return [3 /*break*/, 2];
7818
+ if (!isNil(this.$inputItems.value)) return [3 /*break*/, 2];
7788
7819
  if (this.debug)
7789
7820
  console.debug('[mat-chips] Waiting items to be set...');
7790
7821
  return [4 /*yield*/, firstNotNilPromise(this.$inputItems)];
7791
7822
  case 1:
7792
- _a.sent();
7823
+ _c.sent();
7793
7824
  if (this.debug)
7794
- console.debug('[mat-chips] Received items:', this.$inputItems.getValue());
7795
- _a.label = 2;
7825
+ console.debug('[mat-chips] Received items:', this.$inputItems.value);
7826
+ _c.label = 2;
7796
7827
  case 2:
7797
7828
  this.suggestFn = suggestFromArrayFn_1;
7798
- return [2 /*return*/, this.suggest(value, filter)]; // Loop
7829
+ return [2 /*return*/, this.suggestFn(value, filter)]; // Loop
7799
7830
  }
7800
7831
  });
7801
7832
  }); };
7802
7833
  }
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(
7834
+ // Send value to suggest when :
7835
+ // - is nil and '*', and no min length threshold
7836
+ // - is not nil and not a string type (e.g. object)
7837
+ // - is not nil and is a string, and has enough character
7838
+ var thresholdFilterFn = function (value) { return (isNilOrBlank(value) || (value === '*')
7839
+ ? (_this.suggestLengthThreshold <= 0)
7840
+ : (!(typeof value === 'string')
7841
+ || value.length >= _this.suggestLengthThreshold)); };
7842
+ var filteredItemsChanges = rxjs.merge(
7843
+ // Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
7844
+ this._reload$, this.inputControl.valueChanges
7845
+ .pipe(operators.filter(function (value) { return _this.enabled && isNotNilString(value); }),
7846
+ // Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
7847
+ operators.tap(function (_) { return _this.showLoadingSpinner && _this.markAsLoading(); }),
7848
+ // Filter if not enough character
7849
+ operators.filter(function (value) { return value.length >= _this.suggestLengthThreshold; }),
7850
+ // Wait a debounce time
7851
+ operators.debounceTime(this.debounceTime)
7852
+ // DEBUG
7853
+ //tap((value) => console.debug(this.logPrefix + ' Search text changes:', value))
7854
+ ),
7855
+ // Object set: use it (no distinctUntilChanged() pipe need)
7856
+ this.inputControl.valueChanges
7857
+ .pipe(operators.startWith(this.inputControl.value), operators.filter(function (value) { return isNotNil(value) && typeof value === 'object'; }), operators.tap(function (value) {
7858
+ // DEBUG
7859
+ //console.debug(this.logPrefix + ' object changes:', value)
7860
+ // Update the display value (if need)
7861
+ var displayValue = _this.displayWith(value) || '';
7862
+ // Apply to the input[type=text] field
7863
+ if (_this.matInputText && _this.matInputText.nativeElement) {
7864
+ _this.matInputText.nativeElement.value = displayValue;
7865
+ }
7866
+ })
7867
+ // DEBUG
7868
+ //tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
7869
+ ),
7870
+ // On dropdown button click (no distinctUntilChanged(), nor debounceTime)
7871
+ this.dropButtonClick
7872
+ .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; }),
7873
+ // Make sure there is enough characters
7874
+ operators.filter(thresholdFilterFn)),
7875
+ // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
7876
+ rxjs.merge(
7823
7877
  // Focus or click => Load all
7824
7878
  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); }));
7879
+ .pipe(operators.filter(function (_) { return _this.enabled; }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.inputControl.value; })), rxjs.merge(this.$inputItems, this._$filter)
7880
+ .pipe(operators.filter(function (_) { return _this.enabled; }), operators.map(function (_) { return _this.inputControl.value; })))
7881
+ .pipe(
7882
+ // Make sure there is enough characters
7883
+ operators.filter(thresholdFilterFn),
7884
+ // Distinguish changes
7885
+ operators.distinctUntilChanged()))
7886
+ .pipe(
7887
+ // Suggest values
7888
+ operators.mergeMap(function (value) { return _this.suggest(value, _this.filter); }),
7889
+ // DEBUG
7890
+ //tap(items => console.debug(this.logPrefix + ' Received from suggest: ', items)),
7891
+ // Store implicit value (will use it onBlur if not other value selected)
7892
+ operators.tap(function (items) { return _this.updateImplicitValue(items); }));
7893
+ // Fetch more events
7894
+ var fetchMoreItemsChanges = this._fetchMore$
7895
+ .pipe(operators.tap(function (event) { return event === null || event === void 0 ? void 0 : event.preventDefault(); }), // Avoid to close the mat-select
7896
+ operators.filter(function () { return _this.canFetchMore; }), operators.mergeMap(function () { return _this.fetchMore(); }),
7897
+ // DEBUG
7898
+ //tap(moreItems => console.debug(this.logPrefix + ' Received from fetch More: ', moreItems)),
7899
+ // Concat to existing items
7900
+ operators.map(function (moreItems) { return (_this.$filteredItems.value || []).concat(moreItems); }));
7901
+ // Update filtered items
7902
+ this._subscription.add(rxjs.merge(this.$inputItems,
7903
+ // Update items events
7904
+ filteredItemsChanges,
7905
+ // Fetch more events
7906
+ fetchMoreItemsChanges)
7907
+ // Emit items
7908
+ .subscribe(function (items) { return _this.$filteredItems.next(items); }));
7909
+ // Applying implicit value, on blur
7910
+ this._subscription.add(this.blurred
7911
+ .pipe(operators.map(function (_) { return _this.formControl.value; }))
7912
+ .subscribe(function (value) {
7913
+ // When leave component without object, use implicit value if :
7914
+ // - an explicit value
7915
+ // - field is not empty (user fill something)
7916
+ // - OR field empty but is required
7917
+ if (_this._implicitValue && ((_this.required && isNilOrBlank(value)) || (isNotNilOrBlank(value) && typeof value !== 'object'))) {
7918
+ _this.writeValue(_this._implicitValue);
7919
+ _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7920
+ _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7921
+ _this.checkIfTouched();
7922
+ _this.$filteredItems.next([_this._implicitValue]);
7923
+ }
7924
+ else if (isNilOrBlank(value)) {
7925
+ _this.writeValue(null);
7926
+ _this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
7927
+ _this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
7928
+ _this.checkIfTouched();
7929
+ _this.$filteredItems.next(undefined);
7930
+ }
7931
+ _this._implicitValue = null; // reset the implicit value
7932
+ }));
7933
+ // Listen form control status change
7934
+ this._subscription.add(this.formControl.statusChanges
7935
+ .pipe(
7936
+ //filter(() => this.enabled),
7937
+ operators.distinctUntilChanged())
7938
+ // Update component state
7939
+ .subscribe(function () { return _this.checkIfTouched(); }));
7940
+ this._subscription.add(this.keydownEscape.subscribe(function (event) {
7941
+ if (_this.isOpen) {
7942
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
7943
+ event === null || event === void 0 ? void 0 : event.preventDefault();
7944
+ // DEBUG
7945
+ //console.debug(this.logPrefix + " Closing the panel (keydown.escape)");
7946
+ _this.closePanel();
7947
+ }
7948
+ }));
7836
7949
  };
7837
7950
  MatChipsField.prototype.ngOnDestroy = function () {
7838
7951
  this._subscription.unsubscribe();
7952
+ if (this._itemsSubscription) {
7953
+ this._itemsSubscription.unsubscribe();
7954
+ }
7955
+ if (this._openedSubscription) {
7956
+ this._openedSubscription.unsubscribe();
7957
+ }
7839
7958
  this.$inputItems.complete();
7959
+ this.$filteredItems.complete();
7960
+ this._reload$.complete();
7961
+ this._$filter.complete();
7962
+ this.dropButtonClick.complete();
7963
+ this.clicked.complete();
7964
+ this.blurred.complete();
7965
+ this.focused.complete();
7966
+ this.keydownEscape.complete();
7967
+ this.keyupEnter.complete();
7968
+ this._fetchMore$.complete();
7969
+ this._implicitValue = undefined;
7970
+ this.formControl = null;
7971
+ this.displayWith = null;
7972
+ this.equals = null;
7973
+ this.suggestFn = null;
7974
+ this.$filteredItems = null;
7975
+ this.config = null;
7976
+ this.classList = null;
7977
+ this._onChangeCallback = null;
7978
+ this._onTouchedCallback = null;
7979
+ this._onFetchMoreCallback = null;
7980
+ // Destroy the 'autocomplete' instance, to avoid memory leak
7981
+ if (this.autocomplete) {
7982
+ this.autocomplete.ngOnDestroy();
7983
+ }
7840
7984
  };
7841
7985
  /**
7842
7986
  * Add item to chips
@@ -7857,19 +8001,21 @@
7857
8001
  * @param item
7858
8002
  */
7859
8003
  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('');
8004
+ var value = this.value;
8005
+ var index = value ? value.indexOf(item) : -1;
8006
+ if (index !== -1) {
8007
+ var newValue = value.slice();
8008
+ newValue.splice(index, 1);
8009
+ this.writeValue(newValue);
8010
+ this.closePanel();
7866
8011
  }
7867
8012
  };
7868
8013
  /**
7869
8014
  * Allow to reload content. Useful when filter has been changed but not detected
7870
8015
  */
7871
- MatChipsField.prototype.reloadItems = function () {
7872
- this.onDropButtonClick.emit();
8016
+ MatChipsField.prototype.reloadItems = function (value) {
8017
+ // Force a refresh
8018
+ this._reload$.next(value || '*');
7873
8019
  };
7874
8020
  MatChipsField.prototype.writeValue = function (value) {
7875
8021
  if (this.debug)
@@ -7886,6 +8032,10 @@
7886
8032
  this._onTouchedCallback = fn;
7887
8033
  };
7888
8034
  MatChipsField.prototype.setDisabledState = function (isDisabled) {
8035
+ var _a;
8036
+ if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
8037
+ this.closePanel();
8038
+ }
7889
8039
  this.cd.markForCheck();
7890
8040
  };
7891
8041
  MatChipsField.prototype.focus = function () {
@@ -7905,6 +8055,7 @@
7905
8055
  return false;
7906
8056
  }
7907
8057
  var hasContent = selectInputContent(event);
8058
+ // If combo is empty, or if has content but should force to show panel on focus
7908
8059
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
7909
8060
  if (this.debug)
7910
8061
  console.debug(this.logPrefix + ' Emit focus event');
@@ -7913,20 +8064,83 @@
7913
8064
  }
7914
8065
  return false;
7915
8066
  };
8067
+ MatChipsField.prototype.filterInputTextBlurEvent = function (event) {
8068
+ if (!event || event.defaultPrevented)
8069
+ return;
8070
+ // Ignore event from mat-option
8071
+ if (event.relatedTarget instanceof HTMLElement && event.relatedTarget.tagName === 'MAT-OPTION') {
8072
+ event.preventDefault();
8073
+ if (event.stopPropagation)
8074
+ event.stopPropagation();
8075
+ event.returnValue = false;
8076
+ //DEBUG console.debug(this.logPrefix + " Cancelling blur event");
8077
+ return false;
8078
+ }
8079
+ //DEBUG
8080
+ //console.debug(this.logPrefix + ' Blur: move caret to the beginning');
8081
+ // Move caret to the beginning (fix issue IMAGINE-469)
8082
+ selectInputRange(event.target, 0, 0);
8083
+ this.blurred.emit(event);
8084
+ return true;
8085
+ };
8086
+ MatChipsField.prototype.filterChipsFocusEvent = function (event) {
8087
+ // DEBUG
8088
+ if (this.debug)
8089
+ console.debug(this.logPrefix + ' Focus in chips list', event);
8090
+ // Ignore event in button
8091
+ this.matInputText.nativeElement.focus();
8092
+ };
7916
8093
  MatChipsField.prototype.clearValue = function (event) {
7917
8094
  this.writeValue(null);
7918
8095
  event.stopPropagation();
7919
8096
  };
8097
+ MatChipsField.prototype._initAutocompleteInfiniteScroll = function (threshold) {
8098
+ var _this = this;
8099
+ if (!this.autocomplete)
8100
+ return; // Skip
8101
+ // DEBUG
8102
+ //console.debug(this.logPrefix + ' Init autocomplete scroll listener');
8103
+ if (this._openedSubscription) {
8104
+ this._openedSubscription.unsubscribe();
8105
+ this._subscription.remove(this._openedSubscription);
8106
+ }
8107
+ var opened$ = this.autocomplete._isOpen
8108
+ ? rxjs.timer(0)
8109
+ : this.autocomplete.opened.pipe(operators.debounceTime(200));
8110
+ var scrollEnd$ = opened$
8111
+ .pipe(operators.map(function (_) { return _this.getAutocompletePanel(); }), operators.filter(isNotNil), operators.switchMap(function (panel) { return fromScrollEndEvent(panel, threshold)
8112
+ .pipe(operators.takeUntil(_this.autocomplete.closed)); }));
8113
+ // Trigger fetch more, end end scroll reached
8114
+ this._openedSubscription = scrollEnd$
8115
+ .subscribe(function () { return _this._fetchMore$.emit(); });
8116
+ // Register subscription
8117
+ this._subscription.add(this._openedSubscription);
8118
+ };
8119
+ Object.defineProperty(MatChipsField.prototype, "isOpen", {
8120
+ get: function () {
8121
+ var _a;
8122
+ return ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) || false;
8123
+ },
8124
+ enumerable: false,
8125
+ configurable: true
8126
+ });
8127
+ MatChipsField.prototype.closePanel = function () {
8128
+ var _a, _b;
8129
+ if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
8130
+ (_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
8131
+ return;
8132
+ }
8133
+ };
7920
8134
  /* -- private method -- */
7921
8135
  MatChipsField.prototype.suggest = function (value, filter) {
7922
8136
  return __awaiter(this, void 0, void 0, function () {
7923
8137
  var res, data, total, filteredData;
7924
8138
  var _this = this;
7925
- return __generator(this, function (_a) {
7926
- switch (_a.label) {
8139
+ return __generator(this, function (_c) {
8140
+ switch (_c.label) {
7927
8141
  case 0: return [4 /*yield*/, this.suggestFn(value, filter)];
7928
8142
  case 1:
7929
- res = _a.sent();
8143
+ res = _c.sent();
7930
8144
  // DEBUG
7931
8145
  // console.debug(this.logPrefix + " Filtered items by suggestFn:", value, res);
7932
8146
  if (!res) {
@@ -7942,7 +8156,7 @@
7942
8156
  res = data;
7943
8157
  this._itemCount = toNumber(total, data && data.length || 0);
7944
8158
  }
7945
- filteredData = (res || []).slice().filter(function (item1) { return _this.value.findIndex(function (item2) { return _this.compareWith(item1, item2); }) === -1; });
8159
+ filteredData = (res || []).slice().filter(function (item1) { return _this.value.findIndex(function (item2) { return _this.equals(item1, item2); }) === -1; });
7946
8160
  // Update items count
7947
8161
  this._itemCount = this._itemCount - (((res === null || res === void 0 ? void 0 : res.length) || 0) - ((filteredData === null || filteredData === void 0 ? void 0 : filteredData.length) || 0));
7948
8162
  if (this.debug)
@@ -7952,16 +8166,72 @@
7952
8166
  });
7953
8167
  });
7954
8168
  };
8169
+ MatChipsField.prototype.fetchMore = function () {
8170
+ return __awaiter(this, void 0, void 0, function () {
8171
+ var fetchMoreFn, _c, data, total, fetchMore;
8172
+ return __generator(this, function (_d) {
8173
+ switch (_d.label) {
8174
+ case 0:
8175
+ if (!this._onFetchMoreCallback)
8176
+ return [2 /*return*/, []];
8177
+ fetchMoreFn = this._onFetchMoreCallback;
8178
+ this._onFetchMoreCallback = undefined;
8179
+ return [4 /*yield*/, fetchMoreFn()];
8180
+ case 1:
8181
+ _c = _d.sent(), data = _c.data, total = _c.total, fetchMore = _c.fetchMore;
8182
+ this._itemCount = total || this._itemCount;
8183
+ this._onFetchMoreCallback = fetchMore;
8184
+ this._moreItemsCount = Math.max(0, this._moreItemsCount - data.length); // Borne min = 0
8185
+ return [2 /*return*/, data];
8186
+ }
8187
+ });
8188
+ });
8189
+ };
8190
+ MatChipsField.prototype.updateImplicitValue = function (items) {
8191
+ // Store implicit value (will use it onBlur if not other value selected)
8192
+ if (items && items.length === 1) {
8193
+ this._implicitValue = items[0];
8194
+ //this.formControl.setErrors(null);
8195
+ }
8196
+ else {
8197
+ this._implicitValue = undefined;
8198
+ }
8199
+ };
8200
+ MatChipsField.prototype.getAutocompletePanel = function () {
8201
+ var _a, _b;
8202
+ var ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
8203
+ if (!ele) {
8204
+ // DEBUG
8205
+ console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
8206
+ }
8207
+ return ele;
8208
+ };
8209
+ MatChipsField.prototype.checkIfTouched = function () {
8210
+ if (this.formControl.touched) {
8211
+ this.cd.markForCheck();
8212
+ this._onTouchedCallback();
8213
+ }
8214
+ };
7955
8215
  MatChipsField.prototype.markForCheck = function () {
7956
8216
  this.cd.markForCheck();
7957
8217
  };
8218
+ MatChipsField.prototype.markAsLoading = function () {
8219
+ if (this.$filteredItems.value) {
8220
+ this.$filteredItems.next(undefined);
8221
+ this._itemCount = undefined;
8222
+ this._implicitValue = undefined;
8223
+ this._onFetchMoreCallback = undefined;
8224
+ this._moreItemsCount = 0;
8225
+ this.markForCheck();
8226
+ }
8227
+ };
7958
8228
  return MatChipsField;
7959
8229
  }());
7960
8230
  MatChipsField.decorators = [
7961
8231
  { type: i0.Component, args: [{
7962
8232
  // eslint-disable-next-line @angular-eslint/component-selector
7963
8233
  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",
8234
+ 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",
7965
8235
  providers: [
7966
8236
  {
7967
8237
  provide: i1.NG_VALUE_ACCESSOR,
@@ -7969,8 +8239,9 @@
7969
8239
  useExisting: i0.forwardRef(function () { return MatChipsField; })
7970
8240
  }
7971
8241
  ],
8242
+ encapsulation: i0.ViewEncapsulation.None,
7972
8243
  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%}"]
8244
+ 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
8245
  },] }
7975
8246
  ];
7976
8247
  MatChipsField.ctorParameters = function () { return [
@@ -7978,7 +8249,7 @@
7978
8249
  { type: i1.FormGroupDirective, decorators: [{ type: i0.Optional }] }
7979
8250
  ]; };
7980
8251
  MatChipsField.propDecorators = {
7981
- compareWith: [{ type: i0.Input }],
8252
+ equals: [{ type: i0.Input }],
7982
8253
  logPrefix: [{ type: i0.Input }],
7983
8254
  formControl: [{ type: i0.Input }],
7984
8255
  formControlName: [{ type: i0.Input }],
@@ -7997,16 +8268,27 @@
7997
8268
  highlightAccent: [{ type: i0.Input }],
7998
8269
  showAllOnFocus: [{ type: i0.Input }],
7999
8270
  showPanelOnFocus: [{ type: i0.Input }],
8000
- appAutofocus: [{ type: i0.Input }],
8271
+ autofocus: [{ type: i0.Input }],
8001
8272
  config: [{ type: i0.Input }],
8002
8273
  i18nPrefix: [{ type: i0.Input }],
8003
8274
  noResultMessage: [{ type: i0.Input }],
8004
- class: [{ type: i0.Input }],
8275
+ classList: [{ type: i0.Input, args: ['class',] }],
8276
+ panelWidth: [{ type: i0.Input }],
8277
+ matAutocompletePosition: [{ type: i0.Input }],
8005
8278
  debug: [{ type: i0.Input }],
8279
+ itemSize: [{ type: i0.Input }],
8280
+ fetchMoreThreshold: [{ type: i0.Input }],
8281
+ suggestLengthThreshold: [{ type: i0.Input }],
8282
+ showLoadingSpinner: [{ type: i0.Input }],
8283
+ chipColor: [{ type: i0.Input }],
8006
8284
  clicked: [{ type: i0.Output }],
8007
8285
  blurred: [{ type: i0.Output }],
8008
8286
  focused: [{ type: i0.Output }],
8287
+ dropButtonClick: [{ type: i0.Output }],
8288
+ keydownEscape: [{ type: i0.Output, args: ['keydown.escape',] }],
8289
+ keyupEnter: [{ type: i0.Output, args: ['keyup.enter',] }],
8009
8290
  matInputText: [{ type: i0.ViewChild, args: ['matInputText',] }],
8291
+ autocomplete: [{ type: i0.ViewChild, args: [autocomplete.MatAutocomplete,] }],
8010
8292
  autocompleteTrigger: [{ type: i0.ViewChild, args: [autocomplete.MatAutocompleteTrigger,] }],
8011
8293
  filter: [{ type: i0.Input }],
8012
8294
  tabindex: [{ type: i0.Input }],
@@ -18821,7 +19103,7 @@
18821
19103
  AutocompleteTestPage.decorators = [
18822
19104
  { type: i0.Component, args: [{
18823
19105
  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"
19106
+ template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable&lt;any[]&gt;</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) =&gt; any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter('entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult&lt;any&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [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]=\"compareWithFn\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggest]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable&lt;any[]&gt;</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [equals]=\"compareWithFn\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
18825
19107
  },] }
18826
19108
  ];
18827
19109
  AutocompleteTestPage.ctorParameters = function () { return [
@@ -18992,7 +19274,7 @@
18992
19274
  SwipeTestPage.decorators = [
18993
19275
  { type: i0.Component, args: [{
18994
19276
  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"
19277
+ 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
19278
  },] }
18997
19279
  ];
18998
19280
  SwipeTestPage.ctorParameters = function () { return [
@@ -19109,7 +19391,11 @@
19109
19391
  var FAKE_ENTITIES = [
19110
19392
  { id: 1, label: 'AAA', name: 'Item A' },
19111
19393
  { id: 2, label: 'BBB', name: 'Item B' },
19112
- { id: 3, label: 'CCC', name: 'Item C' }
19394
+ { id: 3, label: 'CCC', name: 'Item C' },
19395
+ { id: 4, label: 'DDD', name: 'Item D' },
19396
+ { id: 5, label: 'EEE', name: 'Item E' },
19397
+ { id: 6, label: 'FFF', name: 'Item F' },
19398
+ { id: 7, label: 'GGG', name: 'Item G' }
19113
19399
  ];
19114
19400
  function deepCopy(values) {
19115
19401
  return (values || FAKE_ENTITIES).map(function (entity) { return Object.assign({}, entity); });
@@ -19133,13 +19419,15 @@
19133
19419
  this.autocompleteFields.add('entity-suggestFn', {
19134
19420
  suggestFn: function (value, filter) { return _this.suggest(value, filter); },
19135
19421
  attributes: ['label', 'name'],
19136
- displayWith: this.entityToString
19422
+ displayWith: this.entityToString,
19423
+ equals: function (o1, o2) { return EntityUtils.compare(o1, o2, 1, 'id') === 0; }
19137
19424
  });
19138
19425
  // From items
19139
19426
  this.autocompleteFields.add('entity-items', {
19140
19427
  items: FAKE_ENTITIES.slice(),
19141
19428
  attributes: ['label', 'name'],
19142
- displayWith: this.entityToString
19429
+ displayWith: this.entityToString,
19430
+ equals: function (o1, o2) { return EntityUtils.compare(o1, o2, 1, 'id') === 0; }
19143
19431
  });
19144
19432
  // From items
19145
19433
  this.autocompleteFields.add('entity-$items', {
@@ -19189,7 +19477,7 @@
19189
19477
  ChipsTestPage.prototype.doSubmit = function (event) {
19190
19478
  console.debug('Validate form: ', this.form.value);
19191
19479
  };
19192
- ChipsTestPage.prototype.compareWithFn = function (o1, o2) {
19480
+ ChipsTestPage.prototype.equals = function (o1, o2) {
19193
19481
  return o1 && o2 && o1.id === o2.id;
19194
19482
  };
19195
19483
  /* -- protected methods -- */
@@ -19201,7 +19489,7 @@
19201
19489
  ChipsTestPage.decorators = [
19202
19490
  { type: i0.Component, args: [{
19203
19491
  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"
19492
+ 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]=\"true\"\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 ></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
19493
  },] }
19206
19494
  ];
19207
19495
  ChipsTestPage.ctorParameters = function () { return [
@@ -19835,12 +20123,23 @@
19835
20123
  };
19836
20124
 
19837
20125
  var AuthModal = /** @class */ (function () {
19838
- function AuthModal(accountService, viewCtrl, changeDetectorRef) {
20126
+ function AuthModal(accountService, viewCtrl, cd) {
19839
20127
  this.accountService = accountService;
19840
20128
  this.viewCtrl = viewCtrl;
19841
- this.changeDetectorRef = changeDetectorRef;
19842
- this.loading = false;
20129
+ this.cd = cd;
19843
20130
  }
20131
+ Object.defineProperty(AuthModal.prototype, "loading", {
20132
+ get: function () {
20133
+ var _a;
20134
+ return (_a = this.form) === null || _a === void 0 ? void 0 : _a.loading;
20135
+ },
20136
+ enumerable: false,
20137
+ configurable: true
20138
+ });
20139
+ AuthModal.prototype.ngOnInit = function () {
20140
+ this.form.markAsReady({ emitEvent: false });
20141
+ this.form.markAsLoaded();
20142
+ };
19844
20143
  AuthModal.prototype.cancel = function () {
19845
20144
  this.viewCtrl.dismiss();
19846
20145
  };
@@ -19848,31 +20147,30 @@
19848
20147
  return __awaiter(this, void 0, void 0, function () {
19849
20148
  var data, account, err_1;
19850
20149
  var _this = this;
19851
- return __generator(this, function (_a) {
19852
- switch (_a.label) {
20150
+ return __generator(this, function (_b) {
20151
+ switch (_b.label) {
19853
20152
  case 0:
19854
20153
  if (this.form.disabled)
19855
20154
  return [2 /*return*/];
19856
20155
  if (!this.form.valid) {
19857
- this.form.markAsTouched();
20156
+ this.form.markAllAsTouched();
19858
20157
  return [2 /*return*/];
19859
20158
  }
19860
- this.loading = true;
19861
- _a.label = 1;
20159
+ this.markAsLoading();
20160
+ _b.label = 1;
19862
20161
  case 1:
19863
- _a.trys.push([1, 3, , 4]);
20162
+ _b.trys.push([1, 3, , 4]);
19864
20163
  data = this.form.value;
19865
20164
  // Disable the form
19866
20165
  this.form.disable();
19867
20166
  return [4 /*yield*/, this.accountService.login(data)];
19868
20167
  case 2:
19869
- account = _a.sent();
20168
+ account = _b.sent();
19870
20169
  return [2 /*return*/, this.viewCtrl.dismiss(account)];
19871
20170
  case 3:
19872
- err_1 = _a.sent();
19873
- this.loading = false;
20171
+ err_1 = _b.sent();
19874
20172
  this.form.error = err_1 && err_1.message || err_1;
19875
- this.markForCheck();
20173
+ this.markAsLoaded();
19876
20174
  // Enable the form
19877
20175
  this.form.enable();
19878
20176
  // Reset form error on next changes
@@ -19887,7 +20185,13 @@
19887
20185
  });
19888
20186
  };
19889
20187
  AuthModal.prototype.markForCheck = function () {
19890
- this.changeDetectorRef.markForCheck();
20188
+ this.cd.markForCheck();
20189
+ };
20190
+ AuthModal.prototype.markAsLoading = function (opts) {
20191
+ this.form.markAsLoading(opts);
20192
+ };
20193
+ AuthModal.prototype.markAsLoaded = function (opts) {
20194
+ this.form.markAsLoaded(opts);
19891
20195
  };
19892
20196
  return AuthModal;
19893
20197
  }());
@@ -23673,6 +23977,7 @@
23673
23977
  _this._useValidator = false;
23674
23978
  _this._stopWatching$ = new rxjs.Subject();
23675
23979
  _this._editingRowCount = 0;
23980
+ _this._fetchMoreFn = null;
23676
23981
  _this.loadingSubject = new rxjs.BehaviorSubject(undefined);
23677
23982
  _this._options = Object.assign({ dataServiceOptions: {}, debug: config && config.suppressErrors === false, keepOriginalDataAfterConfirm: false }, config);
23678
23983
  _this._useValidator = isNotNil(validatorService);
@@ -23723,6 +24028,7 @@
23723
24028
  var _this = this;
23724
24029
  this._stopWatching$.next();
23725
24030
  this._editingRowCount = 0;
24031
+ this._fetchMoreFn = null;
23726
24032
  this.markAsLoading();
23727
24033
  return this.dataService.watchAll(offset, size, sortBy, sortDirection, filter, this.serviceOptions)
23728
24034
  .pipe(
@@ -23736,6 +24042,7 @@
23736
24042
  }
23737
24043
  else {
23738
24044
  _this.updateDatasource((res.data || []));
24045
+ _this._fetchMoreFn = res.fetchMore;
23739
24046
  }
23740
24047
  return res;
23741
24048
  }));
@@ -23986,6 +24293,53 @@
23986
24293
  });
23987
24294
  });
23988
24295
  };
24296
+ EntitiesTableDataSource.prototype.getData = function () {
24297
+ return __awaiter(this, void 0, void 0, function () {
24298
+ var rows;
24299
+ return __generator(this, function (_a) {
24300
+ switch (_a.label) {
24301
+ case 0: return [4 /*yield*/, this.getRows()];
24302
+ case 1:
24303
+ rows = _a.sent();
24304
+ return [2 /*return*/, this.getDataFromRows(rows)];
24305
+ }
24306
+ });
24307
+ });
24308
+ };
24309
+ EntitiesTableDataSource.prototype.fetchMore = function (opts) {
24310
+ var _super = Object.create(null, {
24311
+ updateDatasource: { get: function () { return _super_1.prototype.updateDatasource; } }
24312
+ });
24313
+ return __awaiter(this, void 0, void 0, function () {
24314
+ var res, existingData;
24315
+ return __generator(this, function (_a) {
24316
+ switch (_a.label) {
24317
+ case 0:
24318
+ if (!this._fetchMoreFn)
24319
+ return [2 /*return*/, false]; // Avoid multiple call
24320
+ if (this._editingRowCount > 0) {
24321
+ console.warn('Cannot fetch more because still editing row');
24322
+ return [2 /*return*/];
24323
+ }
24324
+ // Fetch next page
24325
+ this._fetchMoreFn = null; // Avoid multiple call
24326
+ return [4 /*yield*/, this._fetchMoreFn()];
24327
+ case 1:
24328
+ res = _a.sent();
24329
+ // Skip if empty (no more data)
24330
+ if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
24331
+ return [2 /*return*/, false];
24332
+ return [4 /*yield*/, this.getData()];
24333
+ case 2:
24334
+ existingData = _a.sent();
24335
+ _super.updateDatasource.call(this, existingData.concat.apply(existingData, __spread(res.data)), opts);
24336
+ // Remember fetchMore
24337
+ this._fetchMoreFn = res.fetchMore;
24338
+ return [2 /*return*/, true];
24339
+ }
24340
+ });
24341
+ });
24342
+ };
23989
24343
  /* -- protected method -- */
23990
24344
  EntitiesTableDataSource.prototype.markAsLoading = function () {
23991
24345
  if (this.loadingSubject.value !== true) {