@firestitch/filter 9.8.7 → 9.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, combineLatest } from 'rxjs';
5
- import { take, takeUntil, debounceTime, tap, distinctUntilChanged, filter as filter$1, switchMap, skip, map, mapTo, startWith, delay } from 'rxjs/operators';
4
+ import { BehaviorSubject, Subject, isObservable, forkJoin, combineLatest, of, fromEvent, 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
- this._initialized = false;
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,18 @@ class BaseItem {
187
194
  get persistanceObject() {
188
195
  return this.queryObject;
189
196
  }
197
+ loadDefaultValue() {
198
+ this._pendingDefaultValue = true;
199
+ return this.defaultValueFn()
200
+ .pipe(tap((value) => {
201
+ this.defaultValue = value;
202
+ this._initDefaultModel();
203
+ }), finalize(() => {
204
+ this._pendingDefaultValue = false;
205
+ }));
206
+ }
190
207
  initValues(persistedValue) {
191
- this._initialized = false;
208
+ // this._initialized = false;
192
209
  this.persistedValue = persistedValue;
193
210
  this._initDefaultModel();
194
211
  const isAutocomplete = this.type === ItemType.AutoComplete || this.type === ItemType.AutoCompleteChips;
@@ -201,12 +218,12 @@ class BaseItem {
201
218
  this.values = valuesResult;
202
219
  // Move to some other place
203
220
  this._init();
204
- this._initialized = true;
221
+ // this._initialized = true;
205
222
  }
206
223
  }
207
224
  else {
208
225
  this._init();
209
- this._initialized = true;
226
+ // this._initialized = true;
210
227
  }
211
228
  }
212
229
  loadAsyncValues(reload = true) {
@@ -220,7 +237,7 @@ class BaseItem {
220
237
  this.loading = false;
221
238
  this._init();
222
239
  this._validateModel();
223
- this._initialized = true;
240
+ // this._initialized = true;
224
241
  });
225
242
  }
226
243
  }
@@ -250,7 +267,12 @@ class BaseItem {
250
267
  this.name = item.name;
251
268
  this.label = item.label;
252
269
  this.chipLabel = item.chipLabel;
253
- this.defaultValue = item.default;
270
+ if (typeof item.default === 'function') {
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.defaultValueFn
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) {
@@ -1948,8 +2003,10 @@ let ExternalParamsController = class ExternalParamsController {
1948
2003
  this._initSavedFilters();
1949
2004
  this._pending$.next(true);
1950
2005
  if (this._savedFilters.enabled) {
1951
- this._savedFilters
1952
- .load()
2006
+ combineLatest([
2007
+ this._itemsStore.ready$,
2008
+ this._savedFilters.load(),
2009
+ ])
1953
2010
  .pipe(takeUntil(this._destroy$))
1954
2011
  .subscribe(() => {
1955
2012
  this._savedFilters.updateActiveFilter();
@@ -1959,8 +2016,12 @@ let ExternalParamsController = class ExternalParamsController {
1959
2016
  });
1960
2017
  }
1961
2018
  else {
1962
- this._initItemsValues();
1963
- this._pending$.next(false);
2019
+ this._itemsStore.ready$
2020
+ .pipe(takeUntil(this._destroy$))
2021
+ .subscribe(() => {
2022
+ this._initItemsValues();
2023
+ this._pending$.next(false);
2024
+ });
1964
2025
  }
1965
2026
  this._listenItemsChange();
1966
2027
  }
@@ -2654,6 +2715,9 @@ let FilterComponent = class FilterComponent {
2654
2715
  get visibleItems() {
2655
2716
  return this._filterItems.visibleItems;
2656
2717
  }
2718
+ get itemsReady$() {
2719
+ return this._filterItems.ready$;
2720
+ }
2657
2721
  get hasFilterChips$() {
2658
2722
  return this._hasFilterChips$.asObservable();
2659
2723
  }
@@ -2685,21 +2749,6 @@ let FilterComponent = class FilterComponent {
2685
2749
  this.focus();
2686
2750
  }
2687
2751
  });
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
2752
  this._listenInternalItemsChange();
2704
2753
  this._initOverlay();
2705
2754
  }
@@ -3088,10 +3137,15 @@ let FilterComponent = class FilterComponent {
3088
3137
  }
3089
3138
  // We may need some time to recieve external params and after that ready can be emitted
3090
3139
  _listenWhenFilterReady() {
3091
- this._externalParams
3092
- .pending$
3093
- .pipe(filter$1((value) => !value), takeUntil(this._destroy$))
3140
+ combineLatest([
3141
+ this._externalParams.pending$,
3142
+ this.itemsReady$,
3143
+ ])
3144
+ .pipe(filter$1(([pendingParams, itemsReady]) => !pendingParams && itemsReady), takeUntil(this._destroy$))
3094
3145
  .subscribe(() => {
3146
+ if (this.config.init) {
3147
+ this.init();
3148
+ }
3095
3149
  this.ready.emit();
3096
3150
  });
3097
3151
  }
@@ -3168,7 +3222,7 @@ __decorate([
3168
3222
  FilterComponent = __decorate([
3169
3223
  Component({
3170
3224
  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 #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",
3225
+ 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
3226
  encapsulation: ViewEncapsulation.None,
3173
3227
  providers: [
3174
3228
  FsFilterOverlayService,