@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.
@@ -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, 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
- 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,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
- this.defaultValue = item.default;
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
- this._externalParams
3092
- .pending$
3093
- .pipe(filter$1((value) => !value), takeUntil(this._destroy$))
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 \">\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",
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,