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