@firestitch/filter 9.8.6 → 9.9.1
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/app/components/filter/filter.component.d.ts +1 -0
- package/app/interfaces/items/base.interface.d.ts +3 -1
- package/app/models/items/base-item.d.ts +6 -2
- package/app/services/items-store.service.d.ts +5 -0
- package/bundles/firestitch-filter.umd.js +97 -27
- package/bundles/firestitch-filter.umd.js.map +1 -1
- package/bundles/firestitch-filter.umd.min.js +2 -2
- package/bundles/firestitch-filter.umd.min.js.map +1 -1
- package/esm2015/app/components/filter/filter.component.js +14 -21
- package/esm2015/app/interfaces/items/base.interface.js +1 -1
- package/esm2015/app/models/items/base-item.js +30 -8
- package/esm2015/app/services/items-store.service.js +38 -5
- package/esm2015/public_api.js +1 -1
- package/esm5/app/components/filter/filter.component.js +22 -22
- package/esm5/app/interfaces/items/base.interface.js +1 -1
- package/esm5/app/models/items/base-item.js +39 -8
- package/esm5/app/services/items-store.service.js +44 -5
- package/esm5/public_api.js +1 -1
- package/fesm2015/firestitch-filter.js +77 -29
- package/fesm2015/firestitch-filter.js.map +1 -1
- package/fesm5/firestitch-filter.js +99 -29
- package/fesm5/firestitch-filter.js.map +1 -1
- package/firestitch-filter.metadata.json +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +5 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __decorate, __metadata, __param } from 'tslib';
|
|
2
2
|
import { Injectable, Optional, Inject, Component, ChangeDetectionStrategy, InjectionToken, ChangeDetectorRef, HostListener, Input, Injector, Directive, EventEmitter, NgZone, Output, ContentChild, TemplateRef, ViewChild, ElementRef, HostBinding, ViewEncapsulation, KeyValueDiffers, Pipe, Self, NgModule } from '@angular/core';
|
|
3
3
|
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
|
4
|
-
import { BehaviorSubject, Subject, isObservable, of, fromEvent, merge, timer
|
|
5
|
-
import {
|
|
4
|
+
import { BehaviorSubject, Subject, isObservable, forkJoin, of, fromEvent, combineLatest, merge, timer } from 'rxjs';
|
|
5
|
+
import { tap, finalize, take, takeUntil, debounceTime, filter as filter$1, distinctUntilChanged, switchMap, skip, map, mapTo, startWith, delay } from 'rxjs/operators';
|
|
6
6
|
import { isFunction, clone, isObject, isString, toString, pickBy } from 'lodash-es';
|
|
7
7
|
import { Model, Alias } from 'tsmodels';
|
|
8
8
|
import { filter, isEmpty, getNormalizedPath, list, remove, FsCommonModule } from '@firestitch/common';
|
|
@@ -68,8 +68,9 @@ function findValue(values, value, children) {
|
|
|
68
68
|
class BaseItem {
|
|
69
69
|
constructor(itemConfig, _additionalConfig) {
|
|
70
70
|
this._additionalConfig = _additionalConfig;
|
|
71
|
-
|
|
71
|
+
// protected _initialized = false;
|
|
72
72
|
this._pendingValues = false;
|
|
73
|
+
this._pendingDefaultValue = false;
|
|
73
74
|
this._loading$ = new BehaviorSubject(false);
|
|
74
75
|
this._value$ = new BehaviorSubject(null);
|
|
75
76
|
this._valueChange$ = new Subject();
|
|
@@ -126,6 +127,9 @@ class BaseItem {
|
|
|
126
127
|
get hasPendingValues() {
|
|
127
128
|
return this._pendingValues;
|
|
128
129
|
}
|
|
130
|
+
get hasPendingDefaultValue() {
|
|
131
|
+
return this._pendingDefaultValue;
|
|
132
|
+
}
|
|
129
133
|
get model() {
|
|
130
134
|
return this._model;
|
|
131
135
|
}
|
|
@@ -163,6 +167,9 @@ class BaseItem {
|
|
|
163
167
|
set loading(value) {
|
|
164
168
|
this._loading$.next(value);
|
|
165
169
|
}
|
|
170
|
+
get _initialized() {
|
|
171
|
+
return !this._pendingDefaultValue && !this._pendingValues;
|
|
172
|
+
}
|
|
166
173
|
valueChanged() {
|
|
167
174
|
this._value$.next(this.value);
|
|
168
175
|
if (this.change) {
|
|
@@ -187,8 +194,17 @@ class BaseItem {
|
|
|
187
194
|
get persistanceObject() {
|
|
188
195
|
return this.queryObject;
|
|
189
196
|
}
|
|
197
|
+
loadDefaultValue() {
|
|
198
|
+
return this.defaultValueFn()
|
|
199
|
+
.pipe(tap((value) => {
|
|
200
|
+
this.defaultValue = value;
|
|
201
|
+
this._initDefaultModel();
|
|
202
|
+
}), finalize(() => {
|
|
203
|
+
this._pendingDefaultValue = false;
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
190
206
|
initValues(persistedValue) {
|
|
191
|
-
this._initialized = false;
|
|
207
|
+
// this._initialized = false;
|
|
192
208
|
this.persistedValue = persistedValue;
|
|
193
209
|
this._initDefaultModel();
|
|
194
210
|
const isAutocomplete = this.type === ItemType.AutoComplete || this.type === ItemType.AutoCompleteChips;
|
|
@@ -201,12 +217,12 @@ class BaseItem {
|
|
|
201
217
|
this.values = valuesResult;
|
|
202
218
|
// Move to some other place
|
|
203
219
|
this._init();
|
|
204
|
-
this._initialized = true;
|
|
220
|
+
// this._initialized = true;
|
|
205
221
|
}
|
|
206
222
|
}
|
|
207
223
|
else {
|
|
208
224
|
this._init();
|
|
209
|
-
this._initialized = true;
|
|
225
|
+
// this._initialized = true;
|
|
210
226
|
}
|
|
211
227
|
}
|
|
212
228
|
loadAsyncValues(reload = true) {
|
|
@@ -220,7 +236,7 @@ class BaseItem {
|
|
|
220
236
|
this.loading = false;
|
|
221
237
|
this._init();
|
|
222
238
|
this._validateModel();
|
|
223
|
-
this._initialized = true;
|
|
239
|
+
// this._initialized = true;
|
|
224
240
|
});
|
|
225
241
|
}
|
|
226
242
|
}
|
|
@@ -250,7 +266,13 @@ class BaseItem {
|
|
|
250
266
|
this.name = item.name;
|
|
251
267
|
this.label = item.label;
|
|
252
268
|
this.chipLabel = item.chipLabel;
|
|
253
|
-
|
|
269
|
+
if (typeof item.default === 'function') {
|
|
270
|
+
this._pendingDefaultValue = true;
|
|
271
|
+
this.defaultValueFn = item.default;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.defaultValue = item.default;
|
|
275
|
+
}
|
|
254
276
|
this.change = item.change;
|
|
255
277
|
this.hide = item.hide;
|
|
256
278
|
this.clearAllowed = (_a = item.clear) !== null && _a !== void 0 ? _a : true;
|
|
@@ -1190,12 +1212,15 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1190
1212
|
this.sortByItem = null;
|
|
1191
1213
|
this.sortDirectionItem = null;
|
|
1192
1214
|
this.keywordItem = null;
|
|
1215
|
+
this._ready$ = new BehaviorSubject(false);
|
|
1193
1216
|
this._items = [];
|
|
1194
1217
|
this._visibleItems$ = new BehaviorSubject([]);
|
|
1195
1218
|
this._itemsByName = new Map();
|
|
1196
1219
|
this._itemsValuesLoaded = false;
|
|
1197
1220
|
this._hasKeyword = false;
|
|
1198
1221
|
this._itemsChange$ = new Subject();
|
|
1222
|
+
this._destroy$ = new Subject();
|
|
1223
|
+
this._lazyInit();
|
|
1199
1224
|
}
|
|
1200
1225
|
get items() {
|
|
1201
1226
|
return this._items;
|
|
@@ -1215,8 +1240,13 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1215
1240
|
get itemsChange$() {
|
|
1216
1241
|
return this._itemsChange$.pipe(debounceTime(30));
|
|
1217
1242
|
}
|
|
1243
|
+
get ready$() {
|
|
1244
|
+
return this._ready$.asObservable();
|
|
1245
|
+
}
|
|
1218
1246
|
ngOnDestroy() {
|
|
1219
1247
|
this.destroyItems();
|
|
1248
|
+
this._destroy$.next();
|
|
1249
|
+
this._destroy$.complete();
|
|
1220
1250
|
}
|
|
1221
1251
|
setConfig(config) {
|
|
1222
1252
|
this._itemsByName.clear();
|
|
@@ -1230,8 +1260,6 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1230
1260
|
this._itemsValuesLoaded = false;
|
|
1231
1261
|
if (Array.isArray(items)) {
|
|
1232
1262
|
this._createItems(items);
|
|
1233
|
-
this.updateVisibleItems();
|
|
1234
|
-
this._setKeywordItem();
|
|
1235
1263
|
}
|
|
1236
1264
|
}
|
|
1237
1265
|
filtersClear() {
|
|
@@ -1270,6 +1298,24 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1270
1298
|
.filter((item) => item.hasPendingValues)
|
|
1271
1299
|
.forEach((item) => item.loadAsyncValues());
|
|
1272
1300
|
}
|
|
1301
|
+
loadAsyncDefaults() {
|
|
1302
|
+
const pendingItems = this.items
|
|
1303
|
+
.filter((item) => {
|
|
1304
|
+
return item.hasPendingDefaultValue
|
|
1305
|
+
&& (item.persistedValue === null || item.persistedValue === undefined);
|
|
1306
|
+
});
|
|
1307
|
+
if (pendingItems.length > 0) {
|
|
1308
|
+
forkJoin(pendingItems
|
|
1309
|
+
.map((item) => item.loadDefaultValue()))
|
|
1310
|
+
.pipe(finalize(() => {
|
|
1311
|
+
this._ready$.next(true);
|
|
1312
|
+
}), takeUntil(this._destroy$))
|
|
1313
|
+
.subscribe();
|
|
1314
|
+
}
|
|
1315
|
+
else {
|
|
1316
|
+
this._ready$.next(true);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1273
1319
|
getSort() {
|
|
1274
1320
|
let sortBy = this.getSortByValue();
|
|
1275
1321
|
sortBy = sortBy === '__all' ? null : sortBy;
|
|
@@ -1324,6 +1370,7 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1324
1370
|
item.initValues(p[item.name]);
|
|
1325
1371
|
});
|
|
1326
1372
|
this._createSortingItems(p);
|
|
1373
|
+
this.loadAsyncDefaults();
|
|
1327
1374
|
this._subscribeToItemsChanges();
|
|
1328
1375
|
}
|
|
1329
1376
|
updateItemsWithValues(values) {
|
|
@@ -1410,6 +1457,14 @@ let FsFilterItemsStore = class FsFilterItemsStore {
|
|
|
1410
1457
|
});
|
|
1411
1458
|
}
|
|
1412
1459
|
}
|
|
1460
|
+
_lazyInit() {
|
|
1461
|
+
this.ready$
|
|
1462
|
+
.pipe(filter$1((state) => state), takeUntil(this._destroy$))
|
|
1463
|
+
.subscribe(() => {
|
|
1464
|
+
this.updateVisibleItems();
|
|
1465
|
+
this._setKeywordItem();
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1413
1468
|
_createSortingItems(p) {
|
|
1414
1469
|
var _a;
|
|
1415
1470
|
if (((_a = this._config.sortValues) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
@@ -2654,6 +2709,9 @@ let FilterComponent = class FilterComponent {
|
|
|
2654
2709
|
get visibleItems() {
|
|
2655
2710
|
return this._filterItems.visibleItems;
|
|
2656
2711
|
}
|
|
2712
|
+
get itemsReady$() {
|
|
2713
|
+
return this._filterItems.ready$;
|
|
2714
|
+
}
|
|
2657
2715
|
get hasFilterChips$() {
|
|
2658
2716
|
return this._hasFilterChips$.asObservable();
|
|
2659
2717
|
}
|
|
@@ -2685,21 +2743,6 @@ let FilterComponent = class FilterComponent {
|
|
|
2685
2743
|
this.focus();
|
|
2686
2744
|
}
|
|
2687
2745
|
});
|
|
2688
|
-
if (this.config.init) {
|
|
2689
|
-
if (this._externalParams.pending) {
|
|
2690
|
-
this._externalParams
|
|
2691
|
-
.pending$
|
|
2692
|
-
.pipe(filter$1((pending) => {
|
|
2693
|
-
return !pending;
|
|
2694
|
-
}), takeUntil(this._destroy$))
|
|
2695
|
-
.subscribe(() => {
|
|
2696
|
-
this.init();
|
|
2697
|
-
});
|
|
2698
|
-
}
|
|
2699
|
-
else {
|
|
2700
|
-
this.init();
|
|
2701
|
-
}
|
|
2702
|
-
}
|
|
2703
2746
|
this._listenInternalItemsChange();
|
|
2704
2747
|
this._initOverlay();
|
|
2705
2748
|
}
|
|
@@ -3088,10 +3131,15 @@ let FilterComponent = class FilterComponent {
|
|
|
3088
3131
|
}
|
|
3089
3132
|
// We may need some time to recieve external params and after that ready can be emitted
|
|
3090
3133
|
_listenWhenFilterReady() {
|
|
3091
|
-
|
|
3092
|
-
.pending
|
|
3093
|
-
|
|
3134
|
+
combineLatest([
|
|
3135
|
+
this._externalParams.pending$,
|
|
3136
|
+
this.itemsReady$,
|
|
3137
|
+
])
|
|
3138
|
+
.pipe(filter$1(([pendingParams, itemsReady]) => !pendingParams && itemsReady), takeUntil(this._destroy$))
|
|
3094
3139
|
.subscribe(() => {
|
|
3140
|
+
if (this.config.init) {
|
|
3141
|
+
this.init();
|
|
3142
|
+
}
|
|
3095
3143
|
this.ready.emit();
|
|
3096
3144
|
});
|
|
3097
3145
|
}
|
|
@@ -3168,7 +3216,7 @@ __decorate([
|
|
|
3168
3216
|
FilterComponent = __decorate([
|
|
3169
3217
|
Component({
|
|
3170
3218
|
selector: 'fs-filter',
|
|
3171
|
-
template: "<ng-container *ngIf=\"hasKeyword; else noKeywordFilter\">\n <div class=\"filter-search-container\">\n <div class=\"filter-input-field\">\n <form autocomplete=\"off\" role=\"presentation\" *ngIf=\"keywordVisible$ | async\">\n <mat-form-field floatLabel=\"never\">\n <span matPrefix>\n <mat-icon matPrefix>search</mat-icon>\n </span>\n\n <input\n matInput\n [formControl]=\"searchText\"\n [placeholder]=\"searchPlaceholder\"\n name=\"filter-input\"\n (click)=\"filterInputEvent($event)\"\n class=\"filter-input\">\n\n <a matSuffix\n *ngIf=\"searchText.value && showFilterInput && config.clear\"\n (click)=\"clearSearchText($event)\"\n href=\"javascript:void(0)\"\n class=\"clear\">\n <mat-icon>clear</mat-icon>\n </a>\n\n <a matSuffix\n (click)=\"reload($event)\"\n class=\"reload\"\n *ngIf=\"config.reload\">\n <mat-icon>refresh</mat-icon>\n </a>\n </mat-form-field>\n </form>\n </div>\n <ng-container *ngTemplateOutlet=\"filterActions\"></ng-container>\n </div>\n <div class=\"status-actions\" *ngIf=\"keywordVisible$ | async\">\n <ng-container *ngTemplateOutlet=\"statusBarContainer\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterChips\"></ng-container>\n </div>\n</ng-container>\n\n<ng-template #noKeywordFilter>\n <div class=\"filter-searchless-container\">\n <div class=\"status-actions\">\n <ng-container *ngTemplateOutlet=\"statusBarContainer\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterChips\"></ng-container>\n </div>\n <ng-container *ngTemplateOutlet=\"filterActions\"></ng-container>\n </div>\n</ng-template>\n\n\n<ng-template #filterActions>\n <div class=\"filter-actions\">\n <ng-container *ngIf=\"hasVisibleItemOrSorting && filtersBtnVisible$ | async
|
|
3219
|
+
template: "<ng-container *ngIf=\"hasKeyword; else noKeywordFilter\">\n <div class=\"filter-search-container\">\n <div class=\"filter-input-field\">\n <form autocomplete=\"off\" role=\"presentation\" *ngIf=\"keywordVisible$ | async\">\n <mat-form-field floatLabel=\"never\">\n <span matPrefix>\n <mat-icon matPrefix>search</mat-icon>\n </span>\n\n <input\n #searchTextInput\n matInput\n [formControl]=\"searchText\"\n [placeholder]=\"searchPlaceholder\"\n name=\"filter-input\"\n (click)=\"filterInputEvent($event)\"\n class=\"filter-input\">\n\n <a matSuffix\n *ngIf=\"searchText.value && showFilterInput && config.clear\"\n (click)=\"clearSearchText($event)\"\n href=\"javascript:void(0)\"\n class=\"clear\">\n <mat-icon>clear</mat-icon>\n </a>\n\n <a matSuffix\n (click)=\"reload($event)\"\n class=\"reload\"\n *ngIf=\"config.reload\">\n <mat-icon>refresh</mat-icon>\n </a>\n </mat-form-field>\n </form>\n </div>\n <ng-container *ngTemplateOutlet=\"filterActions\"></ng-container>\n </div>\n <div class=\"status-actions\" *ngIf=\"keywordVisible$ | async\">\n <ng-container *ngTemplateOutlet=\"statusBarContainer\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterChips\"></ng-container>\n </div>\n</ng-container>\n\n<ng-template #noKeywordFilter>\n <div class=\"filter-searchless-container\">\n <div class=\"status-actions\">\n <ng-container *ngTemplateOutlet=\"statusBarContainer\"></ng-container>\n <ng-container *ngTemplateOutlet=\"filterChips\"></ng-container>\n </div>\n <ng-container *ngTemplateOutlet=\"filterActions\"></ng-container>\n </div>\n</ng-template>\n\n\n<ng-template #filterActions>\n <div class=\"filter-actions\">\n <ng-container *ngIf=\"hasVisibleItemOrSorting && filtersBtnVisible$ | async\">\n <button\n mat-button\n class=\"filters-button\"\n [ngClass]=\"{\n 'mat-raised-button': config.button.style == 'raised',\n 'mat-button': config.button.style == 'basic',\n 'mat-icon-button': config.button.style == 'icon'\n }\"\n (click)=\"changeVisibilityClick(!showFilterMenu, $event)\"\n type=\"button\"\n [color]=\"config.button.color\">\n <mat-icon *ngIf=\"config.button.icon\">{{config.button.icon}}</mat-icon>\n {{ config.button.label }}\n </button>\n </ng-container>\n\n <fs-filter-actions\n *ngIf=\"actionsVisible$ | async\"\n [actions]=\"actions$ | async\"\n [kebabActions]=\"menuActions$ | async\">\n </fs-filter-actions>\n </div>\n</ng-template>\n\n<ng-template #filterChips>\n <fs-filter-chips\n *ngIf=\"config.chips && hasFilterChips$ | async\"\n class=\"filter-chips\"\n [filters]=\"items\">\n </fs-filter-chips>\n</ng-template>\n\n<ng-template #statusBarContainer>\n <div class=\"status-bar\" *ngIf=\"statusBar\">\n <small><ng-container *ngTemplateOutlet=\"statusBar\"></ng-container></small>\n </div>\n</ng-template>\n",
|
|
3172
3220
|
encapsulation: ViewEncapsulation.None,
|
|
3173
3221
|
providers: [
|
|
3174
3222
|
FsFilterOverlayService,
|