@sumaris-net/ngx-components 1.6.0 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/sumaris-net.ngx-components.umd.js +572 -218
- 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 +8 -0
- package/esm2015/src/app/core/auth/modal/modal-auth.js +21 -9
- package/esm2015/src/app/core/table/entities-table-datasource.class.js +35 -1
- package/esm2015/src/app/shared/form/field.model.js +1 -1
- package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +103 -102
- package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +2 -2
- package/esm2015/src/app/shared/material/chips/material.chips.js +354 -81
- package/esm2015/src/app/shared/material/chips/testing/chips.test.js +13 -6
- 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/fesm2015/sumaris-net.ngx-components.js +521 -196
- 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/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 +38 -10
- package/src/app/shared/material/chips/testing/chips.test.d.ts +1 -1
- package/src/app/shared/material/swipe/material.swipe.d.ts +2 -2
- 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, ViewEncapsulation } 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';
|
|
@@ -976,11 +976,10 @@ class MatAutocompleteConfigHolder {
|
|
|
976
976
|
const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
|
|
977
977
|
const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
|
|
978
978
|
const displayWith = options.displayWith || ((obj) => obj && joinPropertiesPath(obj, attributes));
|
|
979
|
-
const compareWith = options.
|
|
979
|
+
const compareWith = options.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
|
|
980
980
|
const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
|
|
981
981
|
filter,
|
|
982
|
-
displayWith,
|
|
983
|
-
compareWith });
|
|
982
|
+
displayWith, equals: compareWith });
|
|
984
983
|
this.fields[fieldName] = config;
|
|
985
984
|
return config;
|
|
986
985
|
}
|
|
@@ -991,11 +990,6 @@ class MatAutocompleteConfigHolder {
|
|
|
991
990
|
return this.fields[fieldName] || this.add(fieldName);
|
|
992
991
|
}
|
|
993
992
|
}
|
|
994
|
-
const DEFAULT_VALUE_ACCESSOR$6 = {
|
|
995
|
-
provide: NG_VALUE_ACCESSOR,
|
|
996
|
-
useExisting: forwardRef(() => MatAutocompleteField),
|
|
997
|
-
multi: true
|
|
998
|
-
};
|
|
999
993
|
const noop$7 = () => { };
|
|
1000
994
|
const ɵ0$a = noop$7;
|
|
1001
995
|
class MatAutocompleteField {
|
|
@@ -1004,14 +998,6 @@ class MatAutocompleteField {
|
|
|
1004
998
|
this.formGroupDir = formGroupDir;
|
|
1005
999
|
this._onChangeCallback = noop$7;
|
|
1006
1000
|
this._onTouchedCallback = noop$7;
|
|
1007
|
-
this._subscription = new Subscription();
|
|
1008
|
-
this._filter$ = new BehaviorSubject(undefined);
|
|
1009
|
-
this._reload$ = new Subject();
|
|
1010
|
-
this._readonly = false;
|
|
1011
|
-
this.$inputItems = new BehaviorSubject(undefined);
|
|
1012
|
-
this.$filteredItems = new BehaviorSubject(undefined);
|
|
1013
|
-
this.displayValue = '';
|
|
1014
|
-
this._fetchMore$ = new EventEmitter();
|
|
1015
1001
|
this.logPrefix = '[mat-autocomplete] ';
|
|
1016
1002
|
this.formControlName = null;
|
|
1017
1003
|
this.required = false;
|
|
@@ -1024,13 +1010,21 @@ class MatAutocompleteField {
|
|
|
1024
1010
|
this.fetchMoreThreshold = '15%';
|
|
1025
1011
|
this.suggestLengthThreshold = null;
|
|
1026
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();
|
|
1027
1019
|
this.animationsDisabled = true;
|
|
1028
|
-
this.
|
|
1029
|
-
this
|
|
1030
|
-
this
|
|
1031
|
-
this.
|
|
1032
|
-
this.
|
|
1033
|
-
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();
|
|
1034
1028
|
}
|
|
1035
1029
|
get itemCount() {
|
|
1036
1030
|
return this._itemCount;
|
|
@@ -1039,14 +1033,14 @@ class MatAutocompleteField {
|
|
|
1039
1033
|
return this._onFetchMoreCallback && this._moreItemsCount > 0;
|
|
1040
1034
|
}
|
|
1041
1035
|
set filter(value) {
|
|
1042
|
-
if (value !== this.
|
|
1036
|
+
if (value !== this._$filter.value) {
|
|
1043
1037
|
// DEBUG
|
|
1044
1038
|
//console.debug(this.logPrefix + " Setting filter:", value);
|
|
1045
|
-
this.
|
|
1039
|
+
this._$filter.next(value);
|
|
1046
1040
|
}
|
|
1047
1041
|
}
|
|
1048
1042
|
get filter() {
|
|
1049
|
-
return this.
|
|
1043
|
+
return this._$filter.value;
|
|
1050
1044
|
}
|
|
1051
1045
|
set readonly(value) {
|
|
1052
1046
|
this._readonly = value;
|
|
@@ -1109,6 +1103,7 @@ class MatAutocompleteField {
|
|
|
1109
1103
|
this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
|
|
1110
1104
|
this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
|
|
1111
1105
|
this.displayWith = this.displayWith || this.config.displayWith;
|
|
1106
|
+
this.equals = this.equals || this.config.equals;
|
|
1112
1107
|
this.mobile = toBoolean(this.mobile, this.config.mobile);
|
|
1113
1108
|
this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
|
|
1114
1109
|
this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
|
|
@@ -1123,20 +1118,18 @@ class MatAutocompleteField {
|
|
|
1123
1118
|
this.displayColumnSizes = this.displayColumnSizes
|
|
1124
1119
|
// if only column: auto size
|
|
1125
1120
|
|| (this.displayAttributes.length === 1 && [undefined])
|
|
1126
|
-
|
|
1127
|
-
//
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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
|
|
1132
1127
|
: undefined));
|
|
1133
1128
|
this.displayColumnNames = this.displayAttributes.map((attr, index) => this.displayColumnNames && this.displayColumnNames[index] ||
|
|
1134
1129
|
(this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()));
|
|
1135
1130
|
this.mobile = toBoolean(this.mobile, false);
|
|
1136
1131
|
this.searchable = !this.mobile && !this.multiple;
|
|
1137
|
-
|
|
1138
|
-
if (!this.searchable && !this.compareWith)
|
|
1139
|
-
this.compareWith = (o1, o2) => o1 && o2 && o1.id === o2.id;
|
|
1132
|
+
this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
|
|
1140
1133
|
const classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
|
|
1141
1134
|
this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
|
|
1142
1135
|
|| (classList.includes('min-width-large') && '400px')
|
|
@@ -1151,7 +1144,7 @@ class MatAutocompleteField {
|
|
|
1151
1144
|
if (!this.suggestFn) {
|
|
1152
1145
|
const suggestFromArrayFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
|
|
1153
1146
|
// DEBUG
|
|
1154
|
-
//console.debug(this.logPrefix +
|
|
1147
|
+
//console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
|
|
1155
1148
|
return suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter));
|
|
1156
1149
|
});
|
|
1157
1150
|
// Wait (once) that items are loaded, then call suggest from array fn
|
|
@@ -1169,10 +1162,18 @@ class MatAutocompleteField {
|
|
|
1169
1162
|
}
|
|
1170
1163
|
else if (!this.searchable) {
|
|
1171
1164
|
// Manually fill input items, from the given suggest function
|
|
1172
|
-
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)
|
|
1173
1166
|
switchMap((filter) => this.suggest('*', filter)))
|
|
1174
1167
|
.subscribe(items => this.$inputItems.next(items)));
|
|
1175
1168
|
}
|
|
1169
|
+
// Send value to suggest when :
|
|
1170
|
+
// - is nil and '*', and no min length threshold
|
|
1171
|
+
// - is not nil and not a string type (e.g. object)
|
|
1172
|
+
// - is not nil and is a string, and has enough character
|
|
1173
|
+
const thresholdFilterFn = (value) => (isNilOrBlank(value) || (value === '*')
|
|
1174
|
+
? (this.suggestLengthThreshold <= 0)
|
|
1175
|
+
: (!(typeof value === 'string')
|
|
1176
|
+
|| value.length >= this.suggestLengthThreshold));
|
|
1176
1177
|
const filteredItemsChanges = merge(
|
|
1177
1178
|
// Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
|
|
1178
1179
|
this._reload$,
|
|
@@ -1180,11 +1181,7 @@ class MatAutocompleteField {
|
|
|
1180
1181
|
this.formControl.valueChanges
|
|
1181
1182
|
.pipe(filter(value => this.enabled && this.searchable && isNotNilString(value)),
|
|
1182
1183
|
// Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
|
|
1183
|
-
tap(
|
|
1184
|
-
if (this.showLoadingSpinner) {
|
|
1185
|
-
this.markAsLoading();
|
|
1186
|
-
}
|
|
1187
|
-
}),
|
|
1184
|
+
tap(_ => this.showLoadingSpinner && this.markAsLoading()),
|
|
1188
1185
|
// Filter if not enough character
|
|
1189
1186
|
filter(value => value.length >= this.suggestLengthThreshold),
|
|
1190
1187
|
// Wait a debounce time
|
|
@@ -1210,28 +1207,24 @@ class MatAutocompleteField {
|
|
|
1210
1207
|
// DEBUG
|
|
1211
1208
|
//tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
|
|
1212
1209
|
),
|
|
1210
|
+
// On dropdown button click (no distinctUntilChanged(), nor debounceTime)
|
|
1211
|
+
this.dropButtonClick
|
|
1212
|
+
.pipe(filter(event => this.searchable && this.enabled && (!event || !event.defaultPrevented)), map(_ => this.showAllOnFocus ? '*' : this.formControl.value),
|
|
1213
|
+
// Make enough characters
|
|
1214
|
+
filter(thresholdFilterFn)),
|
|
1213
1215
|
// Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
|
|
1214
1216
|
merge(
|
|
1215
1217
|
// Focus or click => Load all
|
|
1216
|
-
merge(this.
|
|
1217
|
-
.pipe(filter(_ => this.enabled && this.searchable), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)),
|
|
1218
|
-
|
|
1219
|
-
this.onDropButtonClick
|
|
1220
|
-
.pipe(filter(event => this.enabled && this.searchable && (!event || !event.defaultPrevented)), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)), merge(this.$inputItems, this._filter$)
|
|
1221
|
-
.pipe(filter(event => this.enabled && this.searchable), map(_ => this.formControl.value)))
|
|
1218
|
+
merge(this.focused, this.clicked)
|
|
1219
|
+
.pipe(filter(_ => this.enabled && this.searchable), map(_ => this.showAllOnFocus ? '*' : this.formControl.value)), merge(this.$inputItems, this._$filter)
|
|
1220
|
+
.pipe(filter(_ => this.searchable && this.enabled), map(_ => this.formControl.value)))
|
|
1222
1221
|
.pipe(
|
|
1223
|
-
//
|
|
1224
|
-
|
|
1225
|
-
// - is nil, and there is no min length threshold
|
|
1226
|
-
// - is not nil and not a string type (e.g. object)
|
|
1227
|
-
// - is not nil and is a string, and has enough character
|
|
1228
|
-
filter(value => value === '*'
|
|
1229
|
-
|| (isNil(value)
|
|
1230
|
-
? (this.suggestLengthThreshold <= 0)
|
|
1231
|
-
: (!(typeof value === 'string')
|
|
1232
|
-
|| value.length >= this.suggestLengthThreshold))),
|
|
1222
|
+
// Make enough characters
|
|
1223
|
+
filter(thresholdFilterFn),
|
|
1233
1224
|
// Distinguish changes
|
|
1234
|
-
distinctUntilChanged()
|
|
1225
|
+
distinctUntilChanged(),
|
|
1226
|
+
// DEBUG
|
|
1227
|
+
tap(value => console.debug(this.logPrefix + ' Received update event: ', value))))
|
|
1235
1228
|
.pipe(
|
|
1236
1229
|
// Suggest values
|
|
1237
1230
|
mergeMap(value => this.suggest(value, this.filter)),
|
|
@@ -1257,7 +1250,7 @@ class MatAutocompleteField {
|
|
|
1257
1250
|
// Make sure control value is inside (mat-select)
|
|
1258
1251
|
if (items && !this.searchable) {
|
|
1259
1252
|
const value = this.formControl.value;
|
|
1260
|
-
if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.
|
|
1253
|
+
if (isNotNil(value) && typeof value === 'object' && items.findIndex(item => this.equals(item, value)) === -1) {
|
|
1261
1254
|
// If form value is missing: add it to the list
|
|
1262
1255
|
items = items.concat(value);
|
|
1263
1256
|
}
|
|
@@ -1266,7 +1259,7 @@ class MatAutocompleteField {
|
|
|
1266
1259
|
this.$filteredItems.next(items);
|
|
1267
1260
|
}));
|
|
1268
1261
|
// Applying implicit value, on blur
|
|
1269
|
-
this._subscription.add(this.
|
|
1262
|
+
this._subscription.add(this.blurred
|
|
1270
1263
|
.pipe(
|
|
1271
1264
|
// Skip if not searchable
|
|
1272
1265
|
filter(_ => this.searchable), map(_ => this.formControl.value))
|
|
@@ -1280,12 +1273,14 @@ class MatAutocompleteField {
|
|
|
1280
1273
|
this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
|
|
1281
1274
|
this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
1282
1275
|
this.checkIfTouched();
|
|
1276
|
+
this.$filteredItems.next([this._implicitValue]);
|
|
1283
1277
|
}
|
|
1284
1278
|
else if (isNilOrBlank(value)) {
|
|
1285
1279
|
this.writeValue(null);
|
|
1286
1280
|
this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
|
|
1287
1281
|
this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
1288
1282
|
this.checkIfTouched();
|
|
1283
|
+
this.$filteredItems.next(undefined);
|
|
1289
1284
|
}
|
|
1290
1285
|
this._implicitValue = null; // reset the implicit value
|
|
1291
1286
|
}));
|
|
@@ -1296,7 +1291,7 @@ class MatAutocompleteField {
|
|
|
1296
1291
|
distinctUntilChanged())
|
|
1297
1292
|
// Update component state
|
|
1298
1293
|
.subscribe(() => this.checkIfTouched()));
|
|
1299
|
-
this._subscription.add(this.
|
|
1294
|
+
this._subscription.add(this.keydownEscape.subscribe(event => {
|
|
1300
1295
|
if (this.isOpen) {
|
|
1301
1296
|
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
1302
1297
|
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
@@ -1315,20 +1310,22 @@ class MatAutocompleteField {
|
|
|
1315
1310
|
this._openedSubscription.unsubscribe();
|
|
1316
1311
|
}
|
|
1317
1312
|
this.$inputItems.complete();
|
|
1313
|
+
this.$inputItems.unsubscribe();
|
|
1318
1314
|
this.$filteredItems.complete();
|
|
1315
|
+
this.$filteredItems.unsubscribe();
|
|
1319
1316
|
this._reload$.complete();
|
|
1320
|
-
this.
|
|
1321
|
-
this.
|
|
1322
|
-
this.
|
|
1323
|
-
this.
|
|
1324
|
-
this.
|
|
1325
|
-
this.
|
|
1326
|
-
this.
|
|
1317
|
+
this._$filter.complete();
|
|
1318
|
+
this.dropButtonClick.complete();
|
|
1319
|
+
this.clicked.complete();
|
|
1320
|
+
this.blurred.complete();
|
|
1321
|
+
this.focused.complete();
|
|
1322
|
+
this.keydownEscape.complete();
|
|
1323
|
+
this.keyupEnter.complete();
|
|
1327
1324
|
this._fetchMore$.complete();
|
|
1328
1325
|
this._implicitValue = undefined;
|
|
1329
1326
|
this.formControl = null;
|
|
1330
1327
|
this.displayWith = null;
|
|
1331
|
-
this.
|
|
1328
|
+
this.equals = null;
|
|
1332
1329
|
this.suggestFn = null;
|
|
1333
1330
|
this.$filteredItems = null;
|
|
1334
1331
|
this.matSelectItems$ = null;
|
|
@@ -1338,8 +1335,8 @@ class MatAutocompleteField {
|
|
|
1338
1335
|
this._onTouchedCallback = null;
|
|
1339
1336
|
this._onFetchMoreCallback = null;
|
|
1340
1337
|
// Destroy the 'autocomplete' instance, to avoid memory leak
|
|
1341
|
-
if (this.
|
|
1342
|
-
this.
|
|
1338
|
+
if (this.autocomplete) {
|
|
1339
|
+
this.autocomplete.ngOnDestroy();
|
|
1343
1340
|
}
|
|
1344
1341
|
}
|
|
1345
1342
|
/**
|
|
@@ -1365,7 +1362,7 @@ class MatAutocompleteField {
|
|
|
1365
1362
|
}
|
|
1366
1363
|
setDisabledState(isDisabled) {
|
|
1367
1364
|
var _a;
|
|
1368
|
-
if (isDisabled && ((_a = this.
|
|
1365
|
+
if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
|
|
1369
1366
|
this.closePanel();
|
|
1370
1367
|
}
|
|
1371
1368
|
this.cd.markForCheck();
|
|
@@ -1379,7 +1376,7 @@ class MatAutocompleteField {
|
|
|
1379
1376
|
(_a = this.matSelect) === null || _a === void 0 ? void 0 : _a.focus();
|
|
1380
1377
|
}
|
|
1381
1378
|
}
|
|
1382
|
-
|
|
1379
|
+
filterInputTextFocusEvent(event) {
|
|
1383
1380
|
if (!event || event.defaultPrevented)
|
|
1384
1381
|
return;
|
|
1385
1382
|
// Ignore event from mat-option
|
|
@@ -1388,7 +1385,7 @@ class MatAutocompleteField {
|
|
|
1388
1385
|
if (event.stopPropagation)
|
|
1389
1386
|
event.stopPropagation();
|
|
1390
1387
|
event.returnValue = false;
|
|
1391
|
-
//DEBUG console.debug(this.logPrefix +
|
|
1388
|
+
//DEBUG console.debug(this.logPrefix + ' Cancelling focus event');
|
|
1392
1389
|
return false;
|
|
1393
1390
|
}
|
|
1394
1391
|
const hasContent = selectInputContent(event);
|
|
@@ -1396,7 +1393,7 @@ class MatAutocompleteField {
|
|
|
1396
1393
|
if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
|
|
1397
1394
|
// DEBUG
|
|
1398
1395
|
//console.debug(this.logPrefix + ' Emit focus event');
|
|
1399
|
-
this.
|
|
1396
|
+
this.focused.emit(event);
|
|
1400
1397
|
return true;
|
|
1401
1398
|
}
|
|
1402
1399
|
return false;
|
|
@@ -1417,7 +1414,7 @@ class MatAutocompleteField {
|
|
|
1417
1414
|
//console.debug(this.logPrefix + ' Blur: move caret to the beginning');
|
|
1418
1415
|
// Move caret to the beginning (fix issue IMAGINE-469)
|
|
1419
1416
|
selectInputRange(event.target, 0, 0);
|
|
1420
|
-
this.
|
|
1417
|
+
this.blurred.emit(event);
|
|
1421
1418
|
return true;
|
|
1422
1419
|
}
|
|
1423
1420
|
filterMatSelectFocusEvent(event) {
|
|
@@ -1425,7 +1422,7 @@ class MatAutocompleteField {
|
|
|
1425
1422
|
return;
|
|
1426
1423
|
// DEBUG
|
|
1427
1424
|
// console.debug(this.logPrefix + " Received <mat-select> focus event", event);
|
|
1428
|
-
this.
|
|
1425
|
+
this.focused.emit(event);
|
|
1429
1426
|
}
|
|
1430
1427
|
filterMatSelectBlurEvent(event) {
|
|
1431
1428
|
if (!event || event.defaultPrevented)
|
|
@@ -1442,7 +1439,7 @@ class MatAutocompleteField {
|
|
|
1442
1439
|
// console.debug(this.logPrefix + " Cancelling <mat-select> blur event");
|
|
1443
1440
|
return false;
|
|
1444
1441
|
}
|
|
1445
|
-
this.
|
|
1442
|
+
this.blurred.emit(event);
|
|
1446
1443
|
return true;
|
|
1447
1444
|
}
|
|
1448
1445
|
toggleSearch(event) {
|
|
@@ -1464,7 +1461,7 @@ class MatAutocompleteField {
|
|
|
1464
1461
|
event.stopPropagation();
|
|
1465
1462
|
}
|
|
1466
1463
|
_initAutocompleteInfiniteScroll(threshold) {
|
|
1467
|
-
if (!this.
|
|
1464
|
+
if (!this.autocomplete)
|
|
1468
1465
|
return; // Skip
|
|
1469
1466
|
// DEBUG
|
|
1470
1467
|
//console.debug(this.logPrefix + ' Init autocomplete scroll listener');
|
|
@@ -1472,12 +1469,12 @@ class MatAutocompleteField {
|
|
|
1472
1469
|
this._openedSubscription.unsubscribe();
|
|
1473
1470
|
this._subscription.remove(this._openedSubscription);
|
|
1474
1471
|
}
|
|
1475
|
-
const opened$ = this.
|
|
1472
|
+
const opened$ = this.autocomplete._isOpen
|
|
1476
1473
|
? timer(0)
|
|
1477
|
-
: this.
|
|
1474
|
+
: this.autocomplete.opened.pipe(debounceTime(200));
|
|
1478
1475
|
const scrollEnd$ = opened$
|
|
1479
1476
|
.pipe(map((_) => this.getAutocompletePanel()), filter(isNotNil), switchMap((panel) => fromScrollEndEvent(panel, threshold)
|
|
1480
|
-
.pipe(takeUntil(this.
|
|
1477
|
+
.pipe(takeUntil(this.autocomplete.closed))));
|
|
1481
1478
|
// Trigger fetch more, end end scroll reached
|
|
1482
1479
|
this._openedSubscription = scrollEnd$
|
|
1483
1480
|
.subscribe(() => this._fetchMore$.emit());
|
|
@@ -1508,14 +1505,14 @@ class MatAutocompleteField {
|
|
|
1508
1505
|
}
|
|
1509
1506
|
get isOpen() {
|
|
1510
1507
|
var _a, _b;
|
|
1511
|
-
return (this.searchable && ((_a = this.
|
|
1508
|
+
return (this.searchable && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen))
|
|
1512
1509
|
|| ((_b = this.matSelect) === null || _b === void 0 ? void 0 : _b.panelOpen)
|
|
1513
1510
|
|| false;
|
|
1514
1511
|
}
|
|
1515
1512
|
closePanel() {
|
|
1516
1513
|
var _a, _b, _c, _d;
|
|
1517
|
-
if ((_a = this.
|
|
1518
|
-
(_b = this.
|
|
1514
|
+
if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
|
|
1515
|
+
(_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
|
|
1519
1516
|
return;
|
|
1520
1517
|
}
|
|
1521
1518
|
if ((_c = this.matSelect) === null || _c === void 0 ? void 0 : _c.panelOpen) {
|
|
@@ -1582,7 +1579,7 @@ class MatAutocompleteField {
|
|
|
1582
1579
|
}
|
|
1583
1580
|
getAutocompletePanel() {
|
|
1584
1581
|
var _a, _b;
|
|
1585
|
-
const ele = (_b = (_a = this.
|
|
1582
|
+
const ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
|
|
1586
1583
|
if (!ele) {
|
|
1587
1584
|
// DEBUG
|
|
1588
1585
|
console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
|
|
@@ -1616,10 +1613,14 @@ MatAutocompleteField.decorators = [
|
|
|
1616
1613
|
{ type: Component, args: [{
|
|
1617
1614
|
// eslint-disable-next-line @angular-eslint/component-selector
|
|
1618
1615
|
selector: 'mat-autocomplete-field',
|
|
1619
|
-
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)=\"
|
|
1620
|
-
providers: [
|
|
1616
|
+
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- readonly -->\n <ng-container>\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n </ng-container>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [class.cdk-visually-hidden]=\"!searchable\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
|
|
1617
|
+
providers: [{
|
|
1618
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1619
|
+
multi: true,
|
|
1620
|
+
useExisting: forwardRef(() => MatAutocompleteField)
|
|
1621
|
+
}],
|
|
1621
1622
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1622
|
-
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%}
|
|
1623
|
+
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%}"]
|
|
1623
1624
|
},] }
|
|
1624
1625
|
];
|
|
1625
1626
|
MatAutocompleteField.ctorParameters = () => [
|
|
@@ -1627,7 +1628,7 @@ MatAutocompleteField.ctorParameters = () => [
|
|
|
1627
1628
|
{ type: FormGroupDirective, decorators: [{ type: Optional }] }
|
|
1628
1629
|
];
|
|
1629
1630
|
MatAutocompleteField.propDecorators = {
|
|
1630
|
-
|
|
1631
|
+
equals: [{ type: Input }],
|
|
1631
1632
|
logPrefix: [{ type: Input }],
|
|
1632
1633
|
formControl: [{ type: Input }],
|
|
1633
1634
|
formControlName: [{ type: Input }],
|
|
@@ -1657,21 +1658,21 @@ MatAutocompleteField.propDecorators = {
|
|
|
1657
1658
|
fetchMoreThreshold: [{ type: Input }],
|
|
1658
1659
|
suggestLengthThreshold: [{ type: Input }],
|
|
1659
1660
|
showLoadingSpinner: [{ type: Input }],
|
|
1661
|
+
clicked: [{ type: Output, args: ['click',] }],
|
|
1662
|
+
blurred: [{ type: Output, args: ['blur',] }],
|
|
1663
|
+
focused: [{ type: Output, args: ['focus',] }],
|
|
1664
|
+
dropButtonClick: [{ type: Output }],
|
|
1665
|
+
keydownEscape: [{ type: Output, args: ['keydown.escape',] }],
|
|
1666
|
+
keyupEnter: [{ type: Output, args: ['keyup.enter',] }],
|
|
1667
|
+
matSelect: [{ type: ViewChild, args: ['matSelect',] }],
|
|
1668
|
+
matInputText: [{ type: ViewChild, args: ['matInputText',] }],
|
|
1669
|
+
autocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
|
|
1670
|
+
autocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }],
|
|
1660
1671
|
animationsDisabled: [{ type: HostBinding, args: ['@.disabled',] }],
|
|
1661
1672
|
filter: [{ type: Input }],
|
|
1662
1673
|
readonly: [{ type: Input }],
|
|
1663
1674
|
tabindex: [{ type: Input }],
|
|
1664
|
-
items: [{ type: Input }]
|
|
1665
|
-
onClick: [{ type: Output, args: ['click',] }],
|
|
1666
|
-
onBlur: [{ type: Output, args: ['blur',] }],
|
|
1667
|
-
onFocus: [{ type: Output, args: ['focus',] }],
|
|
1668
|
-
onDropButtonClick: [{ type: Output, args: ['dropButtonClick',] }],
|
|
1669
|
-
onKeydownEscape: [{ type: Output, args: ['keydown.escape',] }],
|
|
1670
|
-
onKeyupEnter: [{ type: Output, args: ['keyup.enter',] }],
|
|
1671
|
-
matSelect: [{ type: ViewChild, args: ['matSelect',] }],
|
|
1672
|
-
matInputText: [{ type: ViewChild, args: ['matInputText',] }],
|
|
1673
|
-
matAutocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
|
|
1674
|
-
matAutocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }]
|
|
1675
|
+
items: [{ type: Input }]
|
|
1675
1676
|
};
|
|
1676
1677
|
|
|
1677
1678
|
class DateFormatPipe {
|
|
@@ -6552,7 +6553,7 @@ class MatSwipeField {
|
|
|
6552
6553
|
// Default values
|
|
6553
6554
|
this.displayAttributes = this.displayAttributes || ['label', 'name'];
|
|
6554
6555
|
this.displayWith = this.displayWith || ((obj) => obj && joinPropertiesPath(obj, this.displayAttributes));
|
|
6555
|
-
this.
|
|
6556
|
+
this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
|
|
6556
6557
|
this.mobile = toBoolean(this.mobile, false);
|
|
6557
6558
|
}
|
|
6558
6559
|
ngOnDestroy() {
|
|
@@ -6612,7 +6613,7 @@ class MatSwipeField {
|
|
|
6612
6613
|
if (this._writing)
|
|
6613
6614
|
return;
|
|
6614
6615
|
this._writing = true;
|
|
6615
|
-
if (!this.
|
|
6616
|
+
if (!this.equals(value, this._value)) {
|
|
6616
6617
|
this._value = value;
|
|
6617
6618
|
this.showSlides = isNotNil(this._value);
|
|
6618
6619
|
this.updateSlides();
|
|
@@ -6696,7 +6697,7 @@ class MatSwipeField {
|
|
|
6696
6697
|
}
|
|
6697
6698
|
updateSlides() {
|
|
6698
6699
|
if (this.showSlides) {
|
|
6699
|
-
const itemIndex = (this.$items.getValue() || []).findIndex(value => this.
|
|
6700
|
+
const itemIndex = (this.$items.getValue() || []).findIndex(value => this.equals(value, this._value));
|
|
6700
6701
|
if (itemIndex >= 0) {
|
|
6701
6702
|
this.slideTo(itemIndex);
|
|
6702
6703
|
}
|
|
@@ -6760,7 +6761,7 @@ MatSwipeField.propDecorators = {
|
|
|
6760
6761
|
required: [{ type: Input }],
|
|
6761
6762
|
mobile: [{ type: Input }],
|
|
6762
6763
|
clearable: [{ type: Input }],
|
|
6763
|
-
|
|
6764
|
+
equals: [{ type: Input }],
|
|
6764
6765
|
displayWith: [{ type: Input }],
|
|
6765
6766
|
displayAttributes: [{ type: Input }],
|
|
6766
6767
|
appAutofocus: [{ type: Input }],
|
|
@@ -6806,36 +6807,48 @@ class MatChipsField {
|
|
|
6806
6807
|
this._onChangeCallback = (_) => { };
|
|
6807
6808
|
this._onTouchedCallback = () => { };
|
|
6808
6809
|
this.logPrefix = '[mat-chips] ';
|
|
6810
|
+
this.formControlName = null;
|
|
6809
6811
|
this.required = false;
|
|
6810
6812
|
this.readonly = false;
|
|
6811
6813
|
this.clearable = false;
|
|
6812
|
-
this.debounceTime =
|
|
6813
|
-
this.highlightAccent = false;
|
|
6814
|
+
this.debounceTime = null;
|
|
6814
6815
|
this.i18nPrefix = 'REFERENTIAL.';
|
|
6815
6816
|
this.noResultMessage = 'COMMON.NO_RESULT';
|
|
6816
6817
|
this.debug = false;
|
|
6818
|
+
this.itemSize = '48px';
|
|
6819
|
+
this.fetchMoreThreshold = '15%';
|
|
6820
|
+
this.suggestLengthThreshold = null;
|
|
6821
|
+
this.showLoadingSpinner = true;
|
|
6822
|
+
this.chipColor = null;
|
|
6817
6823
|
this.clicked = new EventEmitter();
|
|
6818
6824
|
this.blurred = new EventEmitter();
|
|
6819
6825
|
this.focused = new EventEmitter();
|
|
6826
|
+
this.dropButtonClick = new EventEmitter(true);
|
|
6827
|
+
this.keydownEscape = new EventEmitter();
|
|
6828
|
+
this.keyupEnter = new EventEmitter();
|
|
6820
6829
|
this.$inputItems = new BehaviorSubject(undefined);
|
|
6821
|
-
this
|
|
6830
|
+
this.$filteredItems = new BehaviorSubject(undefined);
|
|
6822
6831
|
this.inputControl = new FormControl();
|
|
6823
|
-
this.
|
|
6832
|
+
this._fetchMore$ = new EventEmitter();
|
|
6824
6833
|
this._subscription = new Subscription();
|
|
6825
6834
|
this._$filter = new BehaviorSubject(undefined);
|
|
6835
|
+
this._reload$ = new Subject();
|
|
6826
6836
|
}
|
|
6827
6837
|
get itemCount() {
|
|
6828
6838
|
return this._itemCount;
|
|
6829
6839
|
}
|
|
6840
|
+
get canFetchMore() {
|
|
6841
|
+
return this._onFetchMoreCallback && this._moreItemsCount > 0;
|
|
6842
|
+
}
|
|
6830
6843
|
set filter(value) {
|
|
6831
|
-
if (this.
|
|
6832
|
-
|
|
6833
|
-
|
|
6844
|
+
if (value !== this._$filter.value) {
|
|
6845
|
+
// DEBUG
|
|
6846
|
+
//console.debug(this.logPrefix + " Setting filter:", value);
|
|
6834
6847
|
this._$filter.next(value);
|
|
6835
6848
|
}
|
|
6836
6849
|
}
|
|
6837
6850
|
get filter() {
|
|
6838
|
-
return this._$filter.
|
|
6851
|
+
return this._$filter.value;
|
|
6839
6852
|
}
|
|
6840
6853
|
set tabindex(value) {
|
|
6841
6854
|
this._tabindex = value;
|
|
@@ -6847,19 +6860,25 @@ class MatChipsField {
|
|
|
6847
6860
|
set items(value) {
|
|
6848
6861
|
// Remove previous subscription on items, (if exits)
|
|
6849
6862
|
if (this._itemsSubscription) {
|
|
6850
|
-
console.warn('Items received twice !');
|
|
6863
|
+
console.warn(this.logPrefix + ' Items received twice !');
|
|
6851
6864
|
this._subscription.remove(this._itemsSubscription);
|
|
6852
6865
|
this._itemsSubscription.unsubscribe();
|
|
6853
6866
|
}
|
|
6854
6867
|
if (isObservable(value)) {
|
|
6855
|
-
this._itemsSubscription = this._subscription.add(value.subscribe(v =>
|
|
6868
|
+
this._itemsSubscription = this._subscription.add(value.subscribe(v => {
|
|
6869
|
+
//console.warn(this.logPrefix + " Received items: ", v);
|
|
6870
|
+
this.$inputItems.next(v);
|
|
6871
|
+
}));
|
|
6856
6872
|
}
|
|
6857
6873
|
else {
|
|
6858
|
-
if (value !== this.$inputItems.
|
|
6874
|
+
if (value !== this.$inputItems.value) {
|
|
6859
6875
|
this.$inputItems.next(value);
|
|
6860
6876
|
}
|
|
6861
6877
|
}
|
|
6862
6878
|
}
|
|
6879
|
+
get items() {
|
|
6880
|
+
return this.$inputItems;
|
|
6881
|
+
}
|
|
6863
6882
|
get value() {
|
|
6864
6883
|
return this.formControl.value || [];
|
|
6865
6884
|
}
|
|
@@ -6870,6 +6889,7 @@ class MatChipsField {
|
|
|
6870
6889
|
return !this.readonly && this.formControl.enabled;
|
|
6871
6890
|
}
|
|
6872
6891
|
ngOnInit() {
|
|
6892
|
+
var _a, _b;
|
|
6873
6893
|
this.formControl = this.formControl || this.formControlName && this.formGroupDir && this.formGroupDir.form.get(this.formControlName);
|
|
6874
6894
|
if (!this.formControl)
|
|
6875
6895
|
throw new Error('Missing mandatory attribute \'formControl\' or \'formControlName\' in <mat-chips-field>.');
|
|
@@ -6884,85 +6904,212 @@ class MatChipsField {
|
|
|
6884
6904
|
this.displayColumnSizes = this.displayColumnSizes || this.config.columnSizes;
|
|
6885
6905
|
this.displayColumnNames = this.displayColumnNames || this.config.columnNames;
|
|
6886
6906
|
this.displayWith = this.displayWith || this.config.displayWith;
|
|
6887
|
-
this.
|
|
6907
|
+
this.equals = this.equals || this.config.equals;
|
|
6888
6908
|
this.mobile = toBoolean(this.mobile, this.config.mobile);
|
|
6889
|
-
this.
|
|
6909
|
+
this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
|
|
6910
|
+
this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
|
|
6890
6911
|
this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus, true));
|
|
6891
|
-
this.
|
|
6912
|
+
this.classList = this.classList || this.config.class;
|
|
6913
|
+
this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
|
|
6914
|
+
this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
|
|
6892
6915
|
}
|
|
6893
6916
|
// Default values
|
|
6894
|
-
this.displayAttributes = this.displayAttributes || (this.filter
|
|
6917
|
+
this.displayAttributes = this.displayAttributes || ((_a = this.filter) === null || _a === void 0 ? void 0 : _a.attributes) || ['label', 'name'];
|
|
6895
6918
|
this.displayWith = this.displayWith || ((obj) => obj && joinPropertiesPath(obj, this.displayAttributes));
|
|
6896
|
-
this.
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
//
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6919
|
+
this.displayColumnSizes = this.displayColumnSizes
|
|
6920
|
+
// if only column: auto size
|
|
6921
|
+
|| (this.displayAttributes.length === 1 && [undefined])
|
|
6922
|
+
// Computed column size:
|
|
6923
|
+
// - if label then col size = 2
|
|
6924
|
+
// - if rankOrder then col size = 1
|
|
6925
|
+
// - ese => auto size
|
|
6926
|
+
|| this.displayAttributes.map(attr => (attr && attr.endsWith('label')) ? 2
|
|
6927
|
+
: ((attr && attr.endsWith('rankOrder')) ? 1
|
|
6928
|
+
: undefined));
|
|
6904
6929
|
this.displayColumnNames = this.displayAttributes.map((attr, index) => this.displayColumnNames && this.displayColumnNames[index] ||
|
|
6905
6930
|
(this.i18nPrefix + changeCaseToUnderscore(attr).toUpperCase()));
|
|
6906
6931
|
this.mobile = toBoolean(this.mobile, false);
|
|
6932
|
+
this.equals = this.equals || ((o1, o2) => o1 && o2 && o1.id === o2.id);
|
|
6933
|
+
const classList = (_b = this.classList) === null || _b === void 0 ? void 0 : _b.split(' ');
|
|
6934
|
+
this.panelWidth = this.panelWidth || (classList && ((classList.includes('min-width-medium') && '300px')
|
|
6935
|
+
|| (classList.includes('min-width-large') && '400px')
|
|
6936
|
+
|| (classList.includes('min-width-xlarge') && '450px')
|
|
6937
|
+
|| (classList.includes('mat-autocomplete-panel-full-size') && '100vw')));
|
|
6938
|
+
this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, true);
|
|
6939
|
+
this.debounceTime = toNumber(this.debounceTime, 250);
|
|
6940
|
+
this.highlightAccent = toBoolean(this.highlightAccent, false);
|
|
6941
|
+
this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
|
|
6942
|
+
this.matAutocompletePosition = this.matAutocompletePosition || (this.mobile ? 'above' : 'auto'); // On mobile, set position to above (because of bottom keyboard)
|
|
6907
6943
|
// No suggestFn: filter on the given items
|
|
6908
6944
|
if (!this.suggestFn) {
|
|
6909
6945
|
const suggestFromArrayFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
|
|
6910
6946
|
if (this.debug)
|
|
6911
6947
|
console.debug(this.logPrefix + ' Calling suggestFromArray with value=', value);
|
|
6912
|
-
|
|
6913
|
-
this._itemCount = toNumber(total, data && data.length || 0);
|
|
6914
|
-
return { data, total };
|
|
6948
|
+
return suggestFromArray(this.$inputItems.value, value, Object.assign({ searchAttributes: this.displayAttributes }, filter));
|
|
6915
6949
|
});
|
|
6916
6950
|
// Wait (once) that items are loaded, then call suggest from array fn
|
|
6917
6951
|
this.suggestFn = (value, filter) => __awaiter(this, void 0, void 0, function* () {
|
|
6918
|
-
if (isNil(this.$inputItems.
|
|
6952
|
+
if (isNil(this.$inputItems.value)) {
|
|
6919
6953
|
if (this.debug)
|
|
6920
6954
|
console.debug('[mat-chips] Waiting items to be set...');
|
|
6921
6955
|
yield firstNotNilPromise(this.$inputItems);
|
|
6922
6956
|
if (this.debug)
|
|
6923
|
-
console.debug('[mat-chips] Received items:', this.$inputItems.
|
|
6957
|
+
console.debug('[mat-chips] Received items:', this.$inputItems.value);
|
|
6924
6958
|
}
|
|
6925
6959
|
this.suggestFn = suggestFromArrayFn;
|
|
6926
|
-
return this.
|
|
6960
|
+
return this.suggestFn(value, filter); // Loop
|
|
6927
6961
|
});
|
|
6928
6962
|
}
|
|
6929
|
-
//
|
|
6930
|
-
//
|
|
6931
|
-
//
|
|
6932
|
-
//
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
//
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
//
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6963
|
+
// Send value to suggest when :
|
|
6964
|
+
// - is nil and '*', and no min length threshold
|
|
6965
|
+
// - is not nil and not a string type (e.g. object)
|
|
6966
|
+
// - is not nil and is a string, and has enough character
|
|
6967
|
+
const thresholdFilterFn = (value) => (isNilOrBlank(value) || (value === '*')
|
|
6968
|
+
? (this.suggestLengthThreshold <= 0)
|
|
6969
|
+
: (!(typeof value === 'string')
|
|
6970
|
+
|| value.length >= this.suggestLengthThreshold));
|
|
6971
|
+
const filteredItemsChanges = merge(
|
|
6972
|
+
// Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
|
|
6973
|
+
this._reload$, this.inputControl.valueChanges
|
|
6974
|
+
.pipe(filter(value => this.enabled && isNotNilString(value)),
|
|
6975
|
+
// Mark as loading (to show loading spinner) - earlier as possible, so before the debounce time
|
|
6976
|
+
tap(_ => this.showLoadingSpinner && this.markAsLoading()),
|
|
6977
|
+
// Filter if not enough character
|
|
6978
|
+
filter(value => value.length >= this.suggestLengthThreshold),
|
|
6979
|
+
// Wait a debounce time
|
|
6980
|
+
debounceTime(this.debounceTime)
|
|
6981
|
+
// DEBUG
|
|
6982
|
+
//tap((value) => console.debug(this.logPrefix + ' Search text changes:', value))
|
|
6983
|
+
),
|
|
6984
|
+
// Object set: use it (no distinctUntilChanged() pipe need)
|
|
6985
|
+
this.inputControl.valueChanges
|
|
6986
|
+
.pipe(startWith(this.inputControl.value), filter(value => isNotNil(value) && typeof value === 'object'), tap(value => {
|
|
6987
|
+
// DEBUG
|
|
6988
|
+
//console.debug(this.logPrefix + ' object changes:', value)
|
|
6989
|
+
// Update the display value (if need)
|
|
6990
|
+
const displayValue = this.displayWith(value) || '';
|
|
6991
|
+
// Apply to the input[type=text] field
|
|
6992
|
+
if (this.matInputText && this.matInputText.nativeElement) {
|
|
6993
|
+
this.matInputText.nativeElement.value = displayValue;
|
|
6994
|
+
}
|
|
6995
|
+
})
|
|
6996
|
+
// DEBUG
|
|
6997
|
+
//tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
|
|
6998
|
+
),
|
|
6999
|
+
// On dropdown button click (no distinctUntilChanged(), nor debounceTime)
|
|
7000
|
+
this.dropButtonClick
|
|
7001
|
+
.pipe(filter(event => this.enabled && (!event || !event.defaultPrevented)), tap(_ => this.matInputText.nativeElement.focus()), map(_ => this.showAllOnFocus ? '*' : this.formControl.value),
|
|
7002
|
+
// Make sure there is enough characters
|
|
7003
|
+
filter(thresholdFilterFn)),
|
|
7004
|
+
// Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
|
|
7005
|
+
merge(
|
|
6949
7006
|
// Focus or click => Load all
|
|
6950
7007
|
merge(this.focused, this.clicked)
|
|
6951
|
-
.pipe(filter(_ => this.enabled), map((_) => this.showAllOnFocus ? '*' : this.inputControl.value)), this.
|
|
6952
|
-
.pipe(
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
7008
|
+
.pipe(filter(_ => this.enabled), map((_) => this.showAllOnFocus ? '*' : this.inputControl.value)), merge(this.$inputItems, this._$filter)
|
|
7009
|
+
.pipe(filter(_ => this.enabled), map(_ => this.inputControl.value)))
|
|
7010
|
+
.pipe(
|
|
7011
|
+
// Make sure there is enough characters
|
|
7012
|
+
filter(thresholdFilterFn),
|
|
7013
|
+
// Distinguish changes
|
|
7014
|
+
distinctUntilChanged()))
|
|
7015
|
+
.pipe(
|
|
7016
|
+
// Suggest values
|
|
7017
|
+
mergeMap(value => this.suggest(value, this.filter)),
|
|
7018
|
+
// DEBUG
|
|
7019
|
+
//tap(items => console.debug(this.logPrefix + ' Received from suggest: ', items)),
|
|
7020
|
+
// Store implicit value (will use it onBlur if not other value selected)
|
|
7021
|
+
tap(items => this.updateImplicitValue(items)));
|
|
7022
|
+
// Fetch more events
|
|
7023
|
+
const fetchMoreItemsChanges = this._fetchMore$
|
|
7024
|
+
.pipe(tap(event => event === null || event === void 0 ? void 0 : event.preventDefault()), // Avoid to close the mat-select
|
|
7025
|
+
filter(() => this.canFetchMore), mergeMap(() => this.fetchMore()),
|
|
7026
|
+
// DEBUG
|
|
7027
|
+
//tap(moreItems => console.debug(this.logPrefix + ' Received from fetch More: ', moreItems)),
|
|
7028
|
+
// Concat to existing items
|
|
7029
|
+
map(moreItems => (this.$filteredItems.value || []).concat(moreItems)));
|
|
7030
|
+
// Update filtered items
|
|
7031
|
+
this._subscription.add(merge(this.$inputItems,
|
|
7032
|
+
// Update items events
|
|
7033
|
+
filteredItemsChanges,
|
|
7034
|
+
// Fetch more events
|
|
7035
|
+
fetchMoreItemsChanges)
|
|
7036
|
+
// Emit items
|
|
7037
|
+
.subscribe(items => this.$filteredItems.next(items)));
|
|
7038
|
+
// Applying implicit value, on blur
|
|
7039
|
+
this._subscription.add(this.blurred
|
|
7040
|
+
.pipe(map(_ => this.formControl.value))
|
|
7041
|
+
.subscribe(value => {
|
|
7042
|
+
// When leave component without object, use implicit value if :
|
|
7043
|
+
// - an explicit value
|
|
7044
|
+
// - field is not empty (user fill something)
|
|
7045
|
+
// - OR field empty but is required
|
|
7046
|
+
if (this._implicitValue && ((this.required && isNilOrBlank(value)) || (isNotNilOrBlank(value) && typeof value !== 'object'))) {
|
|
7047
|
+
this.writeValue(this._implicitValue);
|
|
7048
|
+
this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
|
|
7049
|
+
this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
7050
|
+
this.checkIfTouched();
|
|
7051
|
+
this.$filteredItems.next([this._implicitValue]);
|
|
7052
|
+
}
|
|
7053
|
+
else if (isNilOrBlank(value)) {
|
|
7054
|
+
this.writeValue(null);
|
|
7055
|
+
this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
|
|
7056
|
+
this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
7057
|
+
this.checkIfTouched();
|
|
7058
|
+
this.$filteredItems.next(undefined);
|
|
7059
|
+
}
|
|
7060
|
+
this._implicitValue = null; // reset the implicit value
|
|
7061
|
+
}));
|
|
7062
|
+
// Listen form control status change
|
|
7063
|
+
this._subscription.add(this.formControl.statusChanges
|
|
7064
|
+
.pipe(
|
|
7065
|
+
//filter(() => this.enabled),
|
|
7066
|
+
distinctUntilChanged())
|
|
7067
|
+
// Update component state
|
|
7068
|
+
.subscribe(() => this.checkIfTouched()));
|
|
7069
|
+
this._subscription.add(this.keydownEscape.subscribe(event => {
|
|
7070
|
+
if (this.isOpen) {
|
|
7071
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
7072
|
+
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
7073
|
+
// DEBUG
|
|
7074
|
+
//console.debug(this.logPrefix + " Closing the panel (keydown.escape)");
|
|
7075
|
+
this.closePanel();
|
|
7076
|
+
}
|
|
7077
|
+
}));
|
|
6962
7078
|
}
|
|
6963
7079
|
ngOnDestroy() {
|
|
6964
7080
|
this._subscription.unsubscribe();
|
|
7081
|
+
if (this._itemsSubscription) {
|
|
7082
|
+
this._itemsSubscription.unsubscribe();
|
|
7083
|
+
}
|
|
7084
|
+
if (this._openedSubscription) {
|
|
7085
|
+
this._openedSubscription.unsubscribe();
|
|
7086
|
+
}
|
|
6965
7087
|
this.$inputItems.complete();
|
|
7088
|
+
this.$filteredItems.complete();
|
|
7089
|
+
this._reload$.complete();
|
|
7090
|
+
this._$filter.complete();
|
|
7091
|
+
this.dropButtonClick.complete();
|
|
7092
|
+
this.clicked.complete();
|
|
7093
|
+
this.blurred.complete();
|
|
7094
|
+
this.focused.complete();
|
|
7095
|
+
this.keydownEscape.complete();
|
|
7096
|
+
this.keyupEnter.complete();
|
|
7097
|
+
this._fetchMore$.complete();
|
|
7098
|
+
this._implicitValue = undefined;
|
|
7099
|
+
this.formControl = null;
|
|
7100
|
+
this.displayWith = null;
|
|
7101
|
+
this.equals = null;
|
|
7102
|
+
this.suggestFn = null;
|
|
7103
|
+
this.$filteredItems = null;
|
|
7104
|
+
this.config = null;
|
|
7105
|
+
this.classList = null;
|
|
7106
|
+
this._onChangeCallback = null;
|
|
7107
|
+
this._onTouchedCallback = null;
|
|
7108
|
+
this._onFetchMoreCallback = null;
|
|
7109
|
+
// Destroy the 'autocomplete' instance, to avoid memory leak
|
|
7110
|
+
if (this.autocomplete) {
|
|
7111
|
+
this.autocomplete.ngOnDestroy();
|
|
7112
|
+
}
|
|
6966
7113
|
}
|
|
6967
7114
|
/**
|
|
6968
7115
|
* Add item to chips
|
|
@@ -6983,19 +7130,21 @@ class MatChipsField {
|
|
|
6983
7130
|
* @param item
|
|
6984
7131
|
*/
|
|
6985
7132
|
remove(item) {
|
|
6986
|
-
const
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
value.
|
|
6990
|
-
|
|
6991
|
-
this.
|
|
7133
|
+
const value = this.value;
|
|
7134
|
+
const index = value ? value.indexOf(item) : -1;
|
|
7135
|
+
if (index !== -1) {
|
|
7136
|
+
const newValue = value.slice();
|
|
7137
|
+
newValue.splice(index, 1);
|
|
7138
|
+
this.writeValue(newValue);
|
|
7139
|
+
this.closePanel();
|
|
6992
7140
|
}
|
|
6993
7141
|
}
|
|
6994
7142
|
/**
|
|
6995
7143
|
* Allow to reload content. Useful when filter has been changed but not detected
|
|
6996
7144
|
*/
|
|
6997
|
-
reloadItems() {
|
|
6998
|
-
|
|
7145
|
+
reloadItems(value) {
|
|
7146
|
+
// Force a refresh
|
|
7147
|
+
this._reload$.next(value || '*');
|
|
6999
7148
|
}
|
|
7000
7149
|
writeValue(value) {
|
|
7001
7150
|
if (this.debug)
|
|
@@ -7012,6 +7161,10 @@ class MatChipsField {
|
|
|
7012
7161
|
this._onTouchedCallback = fn;
|
|
7013
7162
|
}
|
|
7014
7163
|
setDisabledState(isDisabled) {
|
|
7164
|
+
var _a;
|
|
7165
|
+
if (isDisabled && ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen)) {
|
|
7166
|
+
this.closePanel();
|
|
7167
|
+
}
|
|
7015
7168
|
this.cd.markForCheck();
|
|
7016
7169
|
}
|
|
7017
7170
|
focus() {
|
|
@@ -7031,6 +7184,7 @@ class MatChipsField {
|
|
|
7031
7184
|
return false;
|
|
7032
7185
|
}
|
|
7033
7186
|
const hasContent = selectInputContent(event);
|
|
7187
|
+
// If combo is empty, or if has content but should force to show panel on focus
|
|
7034
7188
|
if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
|
|
7035
7189
|
if (this.debug)
|
|
7036
7190
|
console.debug(this.logPrefix + ' Emit focus event');
|
|
@@ -7039,10 +7193,68 @@ class MatChipsField {
|
|
|
7039
7193
|
}
|
|
7040
7194
|
return false;
|
|
7041
7195
|
}
|
|
7196
|
+
filterInputTextBlurEvent(event) {
|
|
7197
|
+
if (!event || event.defaultPrevented)
|
|
7198
|
+
return;
|
|
7199
|
+
// Ignore event from mat-option
|
|
7200
|
+
if (event.relatedTarget instanceof HTMLElement && event.relatedTarget.tagName === 'MAT-OPTION') {
|
|
7201
|
+
event.preventDefault();
|
|
7202
|
+
if (event.stopPropagation)
|
|
7203
|
+
event.stopPropagation();
|
|
7204
|
+
event.returnValue = false;
|
|
7205
|
+
//DEBUG console.debug(this.logPrefix + " Cancelling blur event");
|
|
7206
|
+
return false;
|
|
7207
|
+
}
|
|
7208
|
+
//DEBUG
|
|
7209
|
+
//console.debug(this.logPrefix + ' Blur: move caret to the beginning');
|
|
7210
|
+
// Move caret to the beginning (fix issue IMAGINE-469)
|
|
7211
|
+
selectInputRange(event.target, 0, 0);
|
|
7212
|
+
this.blurred.emit(event);
|
|
7213
|
+
return true;
|
|
7214
|
+
}
|
|
7215
|
+
filterChipsFocusEvent(event) {
|
|
7216
|
+
// DEBUG
|
|
7217
|
+
if (this.debug)
|
|
7218
|
+
console.debug(this.logPrefix + ' Focus in chips list', event);
|
|
7219
|
+
// Ignore event in button
|
|
7220
|
+
this.matInputText.nativeElement.focus();
|
|
7221
|
+
}
|
|
7042
7222
|
clearValue(event) {
|
|
7043
7223
|
this.writeValue(null);
|
|
7044
7224
|
event.stopPropagation();
|
|
7045
7225
|
}
|
|
7226
|
+
_initAutocompleteInfiniteScroll(threshold) {
|
|
7227
|
+
if (!this.autocomplete)
|
|
7228
|
+
return; // Skip
|
|
7229
|
+
// DEBUG
|
|
7230
|
+
//console.debug(this.logPrefix + ' Init autocomplete scroll listener');
|
|
7231
|
+
if (this._openedSubscription) {
|
|
7232
|
+
this._openedSubscription.unsubscribe();
|
|
7233
|
+
this._subscription.remove(this._openedSubscription);
|
|
7234
|
+
}
|
|
7235
|
+
const opened$ = this.autocomplete._isOpen
|
|
7236
|
+
? timer(0)
|
|
7237
|
+
: this.autocomplete.opened.pipe(debounceTime(200));
|
|
7238
|
+
const scrollEnd$ = opened$
|
|
7239
|
+
.pipe(map((_) => this.getAutocompletePanel()), filter(isNotNil), switchMap((panel) => fromScrollEndEvent(panel, threshold)
|
|
7240
|
+
.pipe(takeUntil(this.autocomplete.closed))));
|
|
7241
|
+
// Trigger fetch more, end end scroll reached
|
|
7242
|
+
this._openedSubscription = scrollEnd$
|
|
7243
|
+
.subscribe(() => this._fetchMore$.emit());
|
|
7244
|
+
// Register subscription
|
|
7245
|
+
this._subscription.add(this._openedSubscription);
|
|
7246
|
+
}
|
|
7247
|
+
get isOpen() {
|
|
7248
|
+
var _a;
|
|
7249
|
+
return ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) || false;
|
|
7250
|
+
}
|
|
7251
|
+
closePanel() {
|
|
7252
|
+
var _a, _b;
|
|
7253
|
+
if ((_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.isOpen) {
|
|
7254
|
+
(_b = this.autocompleteTrigger) === null || _b === void 0 ? void 0 : _b.closePanel();
|
|
7255
|
+
return;
|
|
7256
|
+
}
|
|
7257
|
+
}
|
|
7046
7258
|
/* -- private method -- */
|
|
7047
7259
|
suggest(value, filter) {
|
|
7048
7260
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7064,7 +7276,7 @@ class MatChipsField {
|
|
|
7064
7276
|
this._itemCount = toNumber(total, data && data.length || 0);
|
|
7065
7277
|
}
|
|
7066
7278
|
// Filter out existing items
|
|
7067
|
-
const filteredData = (res || []).slice().filter(item1 => this.value.findIndex(item2 => this.
|
|
7279
|
+
const filteredData = (res || []).slice().filter(item1 => this.value.findIndex(item2 => this.equals(item1, item2)) === -1);
|
|
7068
7280
|
// Update items count
|
|
7069
7281
|
this._itemCount = this._itemCount - (((res === null || res === void 0 ? void 0 : res.length) || 0) - ((filteredData === null || filteredData === void 0 ? void 0 : filteredData.length) || 0));
|
|
7070
7282
|
if (this.debug)
|
|
@@ -7072,15 +7284,64 @@ class MatChipsField {
|
|
|
7072
7284
|
return res;
|
|
7073
7285
|
});
|
|
7074
7286
|
}
|
|
7287
|
+
fetchMore() {
|
|
7288
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7289
|
+
if (!this._onFetchMoreCallback)
|
|
7290
|
+
return [];
|
|
7291
|
+
// Save then remove fetch function (to avoid multi-call)
|
|
7292
|
+
const fetchMoreFn = this._onFetchMoreCallback;
|
|
7293
|
+
this._onFetchMoreCallback = undefined;
|
|
7294
|
+
const { data, total, fetchMore } = yield fetchMoreFn();
|
|
7295
|
+
this._itemCount = total || this._itemCount;
|
|
7296
|
+
this._onFetchMoreCallback = fetchMore;
|
|
7297
|
+
this._moreItemsCount = Math.max(0, this._moreItemsCount - data.length); // Borne min = 0
|
|
7298
|
+
return data;
|
|
7299
|
+
});
|
|
7300
|
+
}
|
|
7301
|
+
updateImplicitValue(items) {
|
|
7302
|
+
// Store implicit value (will use it onBlur if not other value selected)
|
|
7303
|
+
if (items && items.length === 1) {
|
|
7304
|
+
this._implicitValue = items[0];
|
|
7305
|
+
//this.formControl.setErrors(null);
|
|
7306
|
+
}
|
|
7307
|
+
else {
|
|
7308
|
+
this._implicitValue = undefined;
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
getAutocompletePanel() {
|
|
7312
|
+
var _a, _b;
|
|
7313
|
+
const ele = (_b = (_a = this.autocomplete) === null || _a === void 0 ? void 0 : _a.options.last) === null || _b === void 0 ? void 0 : _b._getHostElement().parentElement;
|
|
7314
|
+
if (!ele) {
|
|
7315
|
+
// DEBUG
|
|
7316
|
+
console.warn(this.logPrefix + ' Unable to find the autocomplete div...');
|
|
7317
|
+
}
|
|
7318
|
+
return ele;
|
|
7319
|
+
}
|
|
7320
|
+
checkIfTouched() {
|
|
7321
|
+
if (this.formControl.touched) {
|
|
7322
|
+
this.cd.markForCheck();
|
|
7323
|
+
this._onTouchedCallback();
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7075
7326
|
markForCheck() {
|
|
7076
7327
|
this.cd.markForCheck();
|
|
7077
7328
|
}
|
|
7329
|
+
markAsLoading() {
|
|
7330
|
+
if (this.$filteredItems.value) {
|
|
7331
|
+
this.$filteredItems.next(undefined);
|
|
7332
|
+
this._itemCount = undefined;
|
|
7333
|
+
this._implicitValue = undefined;
|
|
7334
|
+
this._onFetchMoreCallback = undefined;
|
|
7335
|
+
this._moreItemsCount = 0;
|
|
7336
|
+
this.markForCheck();
|
|
7337
|
+
}
|
|
7338
|
+
}
|
|
7078
7339
|
}
|
|
7079
7340
|
MatChipsField.decorators = [
|
|
7080
7341
|
{ type: Component, args: [{
|
|
7081
7342
|
// eslint-disable-next-line @angular-eslint/component-selector
|
|
7082
7343
|
selector: 'mat-chips-field',
|
|
7083
|
-
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-
|
|
7344
|
+
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\" class=\"material-chips\" [class.mat-form-field-disabled]=\"disabled\">\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n <mat-label>{{placeholder}}</mat-label>\n <mat-chip-list #chipList\n (focus)=\"filterChipsFocusEvent($event)\" >\n <mat-chip\n *ngFor=\"let item of value\"\n [selectable]=\"false\"\n [removable]=\"!disabled\"\n (removed)=\"remove(item)\"\n [color]=\"chipColor\"\n >\n {{displayWith(item)}}\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\n </mat-chip>\n\n <input #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"inputControl\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [readonly]=\"disabled\"\n [hidden]=\"disabled\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\"\n [matChipInputFor]=\"chipList\"\n >\n </mat-chip-list>\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n (optionSelected)=\"add($event)\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: inputControl.value, withAccent: highlightAccent } \"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
|
|
7084
7345
|
providers: [
|
|
7085
7346
|
{
|
|
7086
7347
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -7088,8 +7349,9 @@ MatChipsField.decorators = [
|
|
|
7088
7349
|
useExisting: forwardRef(() => MatChipsField)
|
|
7089
7350
|
}
|
|
7090
7351
|
],
|
|
7352
|
+
encapsulation: ViewEncapsulation.None,
|
|
7091
7353
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
7092
|
-
styles: [":host{position:relative}:host.ion-text-wrap ion-label{white-space:normal!important}button[hidden]{display:none}mat-icon.select-arrow{color:rgba(0,0,0,.47);font-size:150%}"]
|
|
7354
|
+
styles: [":host{width:100%;display:inline-block;position:relative}:host.ion-text-wrap ion-label{white-space:normal!important}button[hidden]{display:none}mat-icon.select-arrow{color:rgba(0,0,0,.47);font-size:150%}.mat-form-field-suffix{position:absolute!important;right:0!important;top:calc(100% - 50px)!important}.mat-chip.mat-standard-chip.mat-primary{background-color:var(--ion-color-primary);color:var(--ion-color-primary-contrast)}.mat-chip.mat-standard-chip.mat-secondary{background-color:var(--ion-color-secondary);color:var(--ion-color-secondary-contrast)}.mat-chip.mat-standard-chip.mat-tertiary{background-color:var(--ion-color-tertiary);color:var(--ion-color-tertiary-contrast)}.mat-chip.mat-standard-chip.mat-accent{background-color:var(--ion-color-accent);color:var(--ion-color-accent-contrast)}.mat-chip.mat-standard-chip.mat-warning{background-color:var(--ion-color-warning);color:var(--ion-color-warning-contrast)}"]
|
|
7093
7355
|
},] }
|
|
7094
7356
|
];
|
|
7095
7357
|
MatChipsField.ctorParameters = () => [
|
|
@@ -7097,7 +7359,7 @@ MatChipsField.ctorParameters = () => [
|
|
|
7097
7359
|
{ type: FormGroupDirective, decorators: [{ type: Optional }] }
|
|
7098
7360
|
];
|
|
7099
7361
|
MatChipsField.propDecorators = {
|
|
7100
|
-
|
|
7362
|
+
equals: [{ type: Input }],
|
|
7101
7363
|
logPrefix: [{ type: Input }],
|
|
7102
7364
|
formControl: [{ type: Input }],
|
|
7103
7365
|
formControlName: [{ type: Input }],
|
|
@@ -7116,16 +7378,27 @@ MatChipsField.propDecorators = {
|
|
|
7116
7378
|
highlightAccent: [{ type: Input }],
|
|
7117
7379
|
showAllOnFocus: [{ type: Input }],
|
|
7118
7380
|
showPanelOnFocus: [{ type: Input }],
|
|
7119
|
-
|
|
7381
|
+
autofocus: [{ type: Input }],
|
|
7120
7382
|
config: [{ type: Input }],
|
|
7121
7383
|
i18nPrefix: [{ type: Input }],
|
|
7122
7384
|
noResultMessage: [{ type: Input }],
|
|
7123
|
-
|
|
7385
|
+
classList: [{ type: Input, args: ['class',] }],
|
|
7386
|
+
panelWidth: [{ type: Input }],
|
|
7387
|
+
matAutocompletePosition: [{ type: Input }],
|
|
7124
7388
|
debug: [{ type: Input }],
|
|
7389
|
+
itemSize: [{ type: Input }],
|
|
7390
|
+
fetchMoreThreshold: [{ type: Input }],
|
|
7391
|
+
suggestLengthThreshold: [{ type: Input }],
|
|
7392
|
+
showLoadingSpinner: [{ type: Input }],
|
|
7393
|
+
chipColor: [{ type: Input }],
|
|
7125
7394
|
clicked: [{ type: Output }],
|
|
7126
7395
|
blurred: [{ type: Output }],
|
|
7127
7396
|
focused: [{ type: Output }],
|
|
7397
|
+
dropButtonClick: [{ type: Output }],
|
|
7398
|
+
keydownEscape: [{ type: Output, args: ['keydown.escape',] }],
|
|
7399
|
+
keyupEnter: [{ type: Output, args: ['keyup.enter',] }],
|
|
7128
7400
|
matInputText: [{ type: ViewChild, args: ['matInputText',] }],
|
|
7401
|
+
autocomplete: [{ type: ViewChild, args: [MatAutocomplete,] }],
|
|
7129
7402
|
autocompleteTrigger: [{ type: ViewChild, args: [MatAutocompleteTrigger,] }],
|
|
7130
7403
|
filter: [{ type: Input }],
|
|
7131
7404
|
tabindex: [{ type: Input }],
|
|
@@ -16367,7 +16640,7 @@ class AutocompleteTestPage {
|
|
|
16367
16640
|
AutocompleteTestPage.decorators = [
|
|
16368
16641
|
{ type: Component, args: [{
|
|
16369
16642
|
selector: 'app-autocomplete-test',
|
|
16370
|
-
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"
|
|
16643
|
+
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></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"compareWithFn\"\n [logPrefix]=\"'[combo-desktop-suggest]'\">\n </mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<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"
|
|
16371
16644
|
},] }
|
|
16372
16645
|
];
|
|
16373
16646
|
AutocompleteTestPage.ctorParameters = () => [
|
|
@@ -16522,7 +16795,7 @@ class SwipeTestPage {
|
|
|
16522
16795
|
SwipeTestPage.decorators = [
|
|
16523
16796
|
{ type: Component, args: [{
|
|
16524
16797
|
selector: 'app-swipe-test',
|
|
16525
|
-
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 [
|
|
16798
|
+
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"
|
|
16526
16799
|
},] }
|
|
16527
16800
|
];
|
|
16528
16801
|
SwipeTestPage.ctorParameters = () => [
|
|
@@ -16628,7 +16901,11 @@ class EntityTestClass {
|
|
|
16628
16901
|
const FAKE_ENTITIES = [
|
|
16629
16902
|
{ id: 1, label: 'AAA', name: 'Item A' },
|
|
16630
16903
|
{ id: 2, label: 'BBB', name: 'Item B' },
|
|
16631
|
-
{ id: 3, label: 'CCC', name: 'Item C' }
|
|
16904
|
+
{ id: 3, label: 'CCC', name: 'Item C' },
|
|
16905
|
+
{ id: 4, label: 'DDD', name: 'Item D' },
|
|
16906
|
+
{ id: 5, label: 'EEE', name: 'Item E' },
|
|
16907
|
+
{ id: 6, label: 'FFF', name: 'Item F' },
|
|
16908
|
+
{ id: 7, label: 'GGG', name: 'Item G' }
|
|
16632
16909
|
];
|
|
16633
16910
|
function deepCopy(values) {
|
|
16634
16911
|
return (values || FAKE_ENTITIES).map(entity => Object.assign({}, entity));
|
|
@@ -16651,13 +16928,15 @@ class ChipsTestPage {
|
|
|
16651
16928
|
this.autocompleteFields.add('entity-suggestFn', {
|
|
16652
16929
|
suggestFn: (value, filter) => this.suggest(value, filter),
|
|
16653
16930
|
attributes: ['label', 'name'],
|
|
16654
|
-
displayWith: this.entityToString
|
|
16931
|
+
displayWith: this.entityToString,
|
|
16932
|
+
equals: (o1, o2) => EntityUtils.compare(o1, o2, 1, 'id') === 0
|
|
16655
16933
|
});
|
|
16656
16934
|
// From items
|
|
16657
16935
|
this.autocompleteFields.add('entity-items', {
|
|
16658
16936
|
items: FAKE_ENTITIES.slice(),
|
|
16659
16937
|
attributes: ['label', 'name'],
|
|
16660
|
-
displayWith: this.entityToString
|
|
16938
|
+
displayWith: this.entityToString,
|
|
16939
|
+
equals: (o1, o2) => EntityUtils.compare(o1, o2, 1, 'id') === 0
|
|
16661
16940
|
});
|
|
16662
16941
|
// From items
|
|
16663
16942
|
this.autocompleteFields.add('entity-$items', {
|
|
@@ -16698,7 +16977,7 @@ class ChipsTestPage {
|
|
|
16698
16977
|
doSubmit(event) {
|
|
16699
16978
|
console.debug('Validate form: ', this.form.value);
|
|
16700
16979
|
}
|
|
16701
|
-
|
|
16980
|
+
equals(o1, o2) {
|
|
16702
16981
|
return o1 && o2 && o1.id === o2.id;
|
|
16703
16982
|
}
|
|
16704
16983
|
/* -- protected methods -- */
|
|
@@ -16709,7 +16988,7 @@ class ChipsTestPage {
|
|
|
16709
16988
|
ChipsTestPage.decorators = [
|
|
16710
16989
|
{ type: Component, args: [{
|
|
16711
16990
|
selector: 'app-chips-test',
|
|
16712
|
-
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
|
|
16991
|
+
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 chipColor=\"accent\"\n [debug]=\"true\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function with initial value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <pre><small>suggestFn: (searchText, filter) => any[]</small></pre>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entityInitial\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [logPrefix]=\"'[mat-chips-initialized] '\"\n chipColor=\"primary\"\n [debug]=\"true\"\n ></mat-chips-field>\n {{stringify(form.controls.entityInitial.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[mat-chips-disabled] '\"\n chipColor=\"warning\"\n ></mat-chips-field>\n {{stringify(form.controls.disableEntity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-chips-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[mat-chips-readonly] '\"\n [readonly]=\"true\"\n ></mat-chips-field>\n {{stringify(form.controls.entity.value)}}\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
|
|
16713
16992
|
},] }
|
|
16714
16993
|
];
|
|
16715
16994
|
ChipsTestPage.ctorParameters = () => [
|
|
@@ -17253,11 +17532,18 @@ AuthForm.propDecorators = {
|
|
|
17253
17532
|
};
|
|
17254
17533
|
|
|
17255
17534
|
class AuthModal {
|
|
17256
|
-
constructor(accountService, viewCtrl,
|
|
17535
|
+
constructor(accountService, viewCtrl, cd) {
|
|
17257
17536
|
this.accountService = accountService;
|
|
17258
17537
|
this.viewCtrl = viewCtrl;
|
|
17259
|
-
this.
|
|
17260
|
-
|
|
17538
|
+
this.cd = cd;
|
|
17539
|
+
}
|
|
17540
|
+
get loading() {
|
|
17541
|
+
var _a;
|
|
17542
|
+
return (_a = this.form) === null || _a === void 0 ? void 0 : _a.loading;
|
|
17543
|
+
}
|
|
17544
|
+
ngOnInit() {
|
|
17545
|
+
this.form.markAsReady({ emitEvent: false });
|
|
17546
|
+
this.form.markAsLoaded();
|
|
17261
17547
|
}
|
|
17262
17548
|
cancel() {
|
|
17263
17549
|
this.viewCtrl.dismiss();
|
|
@@ -17267,10 +17553,10 @@ class AuthModal {
|
|
|
17267
17553
|
if (this.form.disabled)
|
|
17268
17554
|
return;
|
|
17269
17555
|
if (!this.form.valid) {
|
|
17270
|
-
this.form.
|
|
17556
|
+
this.form.markAllAsTouched();
|
|
17271
17557
|
return;
|
|
17272
17558
|
}
|
|
17273
|
-
this.
|
|
17559
|
+
this.markAsLoading();
|
|
17274
17560
|
try {
|
|
17275
17561
|
const data = this.form.value;
|
|
17276
17562
|
// Disable the form
|
|
@@ -17279,9 +17565,8 @@ class AuthModal {
|
|
|
17279
17565
|
return this.viewCtrl.dismiss(account);
|
|
17280
17566
|
}
|
|
17281
17567
|
catch (err) {
|
|
17282
|
-
this.loading = false;
|
|
17283
17568
|
this.form.error = err && err.message || err;
|
|
17284
|
-
this.
|
|
17569
|
+
this.markAsLoaded();
|
|
17285
17570
|
// Enable the form
|
|
17286
17571
|
this.form.enable();
|
|
17287
17572
|
// Reset form error on next changes
|
|
@@ -17294,7 +17579,13 @@ class AuthModal {
|
|
|
17294
17579
|
});
|
|
17295
17580
|
}
|
|
17296
17581
|
markForCheck() {
|
|
17297
|
-
this.
|
|
17582
|
+
this.cd.markForCheck();
|
|
17583
|
+
}
|
|
17584
|
+
markAsLoading(opts) {
|
|
17585
|
+
this.form.markAsLoading(opts);
|
|
17586
|
+
}
|
|
17587
|
+
markAsLoaded(opts) {
|
|
17588
|
+
this.form.markAsLoaded(opts);
|
|
17298
17589
|
}
|
|
17299
17590
|
}
|
|
17300
17591
|
AuthModal.decorators = [
|
|
@@ -20478,6 +20769,7 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
20478
20769
|
this._useValidator = false;
|
|
20479
20770
|
this._stopWatching$ = new Subject();
|
|
20480
20771
|
this._editingRowCount = 0;
|
|
20772
|
+
this._fetchMoreFn = null;
|
|
20481
20773
|
this.loadingSubject = new BehaviorSubject(undefined);
|
|
20482
20774
|
this._options = Object.assign({ dataServiceOptions: {}, debug: config && config.suppressErrors === false, keepOriginalDataAfterConfirm: false }, config);
|
|
20483
20775
|
this._useValidator = isNotNil(validatorService);
|
|
@@ -20510,6 +20802,7 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
20510
20802
|
watchAll(offset, size, sortBy, sortDirection, filter) {
|
|
20511
20803
|
this._stopWatching$.next();
|
|
20512
20804
|
this._editingRowCount = 0;
|
|
20805
|
+
this._fetchMoreFn = null;
|
|
20513
20806
|
this.markAsLoading();
|
|
20514
20807
|
return this.dataService.watchAll(offset, size, sortBy, sortDirection, filter, this.serviceOptions)
|
|
20515
20808
|
.pipe(
|
|
@@ -20523,6 +20816,7 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
20523
20816
|
}
|
|
20524
20817
|
else {
|
|
20525
20818
|
this.updateDatasource((res.data || []));
|
|
20819
|
+
this._fetchMoreFn = res.fetchMore;
|
|
20526
20820
|
}
|
|
20527
20821
|
return res;
|
|
20528
20822
|
}));
|
|
@@ -20751,6 +21045,37 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
20751
21045
|
this._creating = false;
|
|
20752
21046
|
});
|
|
20753
21047
|
}
|
|
21048
|
+
getData() {
|
|
21049
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21050
|
+
const rows = yield this.getRows();
|
|
21051
|
+
return this.getDataFromRows(rows);
|
|
21052
|
+
});
|
|
21053
|
+
}
|
|
21054
|
+
fetchMore(opts) {
|
|
21055
|
+
const _super = Object.create(null, {
|
|
21056
|
+
updateDatasource: { get: () => super.updateDatasource }
|
|
21057
|
+
});
|
|
21058
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21059
|
+
if (!this._fetchMoreFn)
|
|
21060
|
+
return false; // Avoid multiple call
|
|
21061
|
+
if (this._editingRowCount > 0) {
|
|
21062
|
+
console.warn('Cannot fetch more because still editing row');
|
|
21063
|
+
return;
|
|
21064
|
+
}
|
|
21065
|
+
// Fetch next page
|
|
21066
|
+
this._fetchMoreFn = null; // Avoid multiple call
|
|
21067
|
+
const res = yield this._fetchMoreFn();
|
|
21068
|
+
// Skip if empty (no more data)
|
|
21069
|
+
if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
|
|
21070
|
+
return false;
|
|
21071
|
+
// Update the data source
|
|
21072
|
+
const existingData = yield this.getData();
|
|
21073
|
+
_super.updateDatasource.call(this, existingData.concat(...res.data), opts);
|
|
21074
|
+
// Remember fetchMore
|
|
21075
|
+
this._fetchMoreFn = res.fetchMore;
|
|
21076
|
+
return true;
|
|
21077
|
+
});
|
|
21078
|
+
}
|
|
20754
21079
|
/* -- protected method -- */
|
|
20755
21080
|
markAsLoading() {
|
|
20756
21081
|
if (this.loadingSubject.value !== true) {
|