@elderbyte/ngx-starter 16.2.7 → 16.2.9
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/esm2022/lib/common/data/datasource/rest/rest-client.mjs +1 -1
- package/esm2022/lib/components/forms/directives/elder-initial-value.directive.mjs +27 -2
- package/esm2022/lib/components/forms/search/elder-search-context-url-binding.directive.mjs +3 -4
- package/esm2022/lib/components/forms/search/elder-search-context.directive.mjs +48 -74
- package/esm2022/lib/components/forms/search/elder-search-input.directive.mjs +10 -10
- package/esm2022/lib/components/forms/search/model/search-input.mjs +1 -1
- package/esm2022/lib/components/forms/search/search-box/elder-search-box.component.mjs +3 -3
- package/esm2022/lib/components/select/elder-select-base.mjs +21 -2
- package/esm2022/lib/components/select/multi/elder-multi-select-base.mjs +2 -2
- package/esm2022/lib/components/select/single/elder-select/elder-select.component.mjs +12 -9
- package/fesm2022/elderbyte-ngx-starter.mjs +228 -208
- package/fesm2022/elderbyte-ngx-starter.mjs.map +1 -1
- package/lib/components/forms/directives/elder-initial-value.directive.d.ts +21 -0
- package/lib/components/forms/search/elder-search-context.directive.d.ts +12 -21
- package/lib/components/forms/search/elder-search-input.directive.d.ts +4 -5
- package/lib/components/forms/search/model/search-input.d.ts +2 -0
- package/lib/components/select/elder-select-base.d.ts +1 -0
- package/package.json +1 -1
|
@@ -19100,7 +19100,26 @@ class ElderSelectBase extends ElderFormFieldControlBase {
|
|
|
19100
19100
|
* *
|
|
19101
19101
|
**************************************************************************/
|
|
19102
19102
|
getEntityId(entity) {
|
|
19103
|
-
|
|
19103
|
+
try {
|
|
19104
|
+
return this.dataSourceOrThrow().getId(entity);
|
|
19105
|
+
}
|
|
19106
|
+
catch (e) {
|
|
19107
|
+
throw new Error('Failed to extract id from entity since no dataSource is available! Caused by ' + e?.message);
|
|
19108
|
+
}
|
|
19109
|
+
}
|
|
19110
|
+
dataSourceOrThrow() {
|
|
19111
|
+
if (this.dataContext) {
|
|
19112
|
+
const dataSource = this.dataContext.dataSource;
|
|
19113
|
+
if (dataSource) {
|
|
19114
|
+
return dataSource;
|
|
19115
|
+
}
|
|
19116
|
+
else {
|
|
19117
|
+
throw new Error('The provided DataContext has not DataSource, which is required for valueAsId! ' + typeof this.dataContext);
|
|
19118
|
+
}
|
|
19119
|
+
}
|
|
19120
|
+
else {
|
|
19121
|
+
throw new Error('No DataContext available! A DataContext (DataSource) is required for valueAsId!');
|
|
19122
|
+
}
|
|
19104
19123
|
}
|
|
19105
19124
|
isEqual(a, b) {
|
|
19106
19125
|
if (a === b) {
|
|
@@ -19933,7 +19952,7 @@ class ElderSelectComponent extends ElderSelectBase {
|
|
|
19933
19952
|
if (currentEntity && this.getEntityId(currentEntity) === id) {
|
|
19934
19953
|
return; // Entity already loaded
|
|
19935
19954
|
}
|
|
19936
|
-
if (id === null || id === undefined || id ===
|
|
19955
|
+
if (id === null || id === undefined || id === '') {
|
|
19937
19956
|
if (currentEntity !== null && currentEntity !== undefined) {
|
|
19938
19957
|
this.entity = null;
|
|
19939
19958
|
}
|
|
@@ -19954,13 +19973,16 @@ class ElderSelectComponent extends ElderSelectBase {
|
|
|
19954
19973
|
}
|
|
19955
19974
|
}
|
|
19956
19975
|
loadEntityById(id) {
|
|
19957
|
-
this.
|
|
19958
|
-
.subscribe(
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19976
|
+
this.dataSourceOrThrow().findById(id)
|
|
19977
|
+
.subscribe({
|
|
19978
|
+
next: entity => {
|
|
19979
|
+
this.logger.debug('Loaded missing entity by id ' + id + ':', entity);
|
|
19980
|
+
this.entity = entity;
|
|
19981
|
+
},
|
|
19982
|
+
error: err => {
|
|
19983
|
+
this.logger.error('Failed to load entity by id ' + id, err);
|
|
19984
|
+
this.updateState(ElderSelectComponentState.error(err));
|
|
19985
|
+
}
|
|
19964
19986
|
});
|
|
19965
19987
|
}
|
|
19966
19988
|
findInDataContext(id) {
|
|
@@ -21456,7 +21478,7 @@ class ElderMultiSelectBase extends ElderSelectBase {
|
|
|
21456
21478
|
}
|
|
21457
21479
|
}
|
|
21458
21480
|
loadEntitiesByIds(ids) {
|
|
21459
|
-
return this.
|
|
21481
|
+
return this.dataSourceOrThrow().findByIds(ids).pipe(catchError(err => {
|
|
21460
21482
|
this.logger.error('Failed to load entities by ids: ' + ids, err);
|
|
21461
21483
|
return throwError(err);
|
|
21462
21484
|
}), map(values => {
|
|
@@ -25518,6 +25540,166 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImpor
|
|
|
25518
25540
|
type: Input
|
|
25519
25541
|
}] } });
|
|
25520
25542
|
|
|
25543
|
+
/**
|
|
25544
|
+
* The search container manages a group of search-inputs
|
|
25545
|
+
* and holds their values in a central search model.
|
|
25546
|
+
*/
|
|
25547
|
+
class ElderSearchContextDirective {
|
|
25548
|
+
constructor() {
|
|
25549
|
+
/***************************************************************************
|
|
25550
|
+
* *
|
|
25551
|
+
* Fields *
|
|
25552
|
+
* *
|
|
25553
|
+
**************************************************************************/
|
|
25554
|
+
this.forcedFilters$ = new BehaviorSubject$1([]);
|
|
25555
|
+
this.startFilters$ = new BehaviorSubject$1([]);
|
|
25556
|
+
this.log = LoggerFactory.getLogger(this.constructor.name);
|
|
25557
|
+
this.destroy$ = new Subject$1();
|
|
25558
|
+
this._searchInputs = new BehaviorSubject$1([]);
|
|
25559
|
+
this._searchStates = new BehaviorSubject$1([]);
|
|
25560
|
+
this._filters$ = new BehaviorSubject$1([]);
|
|
25561
|
+
this._initialFilters$ = new BehaviorSubject$1([]);
|
|
25562
|
+
}
|
|
25563
|
+
/***************************************************************************
|
|
25564
|
+
* *
|
|
25565
|
+
* Life Cycle *
|
|
25566
|
+
* *
|
|
25567
|
+
**************************************************************************/
|
|
25568
|
+
ngAfterContentInit() {
|
|
25569
|
+
this._searchInputs.pipe(takeUntil(this.destroy$), switchMap(inputs => combineLatest(inputs.map(i => i.state$))), combineLatestWith(this.forcedFilters$), debounceTime(5)).subscribe(([states, forcedFilters]) => {
|
|
25570
|
+
this._searchStates.next(states);
|
|
25571
|
+
const userFilters = this.convertToFilters(states);
|
|
25572
|
+
this._filters$.next(userFilters);
|
|
25573
|
+
this.applyFilters(userFilters, forcedFilters);
|
|
25574
|
+
});
|
|
25575
|
+
}
|
|
25576
|
+
ngAfterViewInit() {
|
|
25577
|
+
this.subscribeInitialFilters();
|
|
25578
|
+
}
|
|
25579
|
+
ngOnDestroy() {
|
|
25580
|
+
this.destroy$.next();
|
|
25581
|
+
this.destroy$.complete();
|
|
25582
|
+
}
|
|
25583
|
+
/***************************************************************************
|
|
25584
|
+
* *
|
|
25585
|
+
* Properties *
|
|
25586
|
+
* *
|
|
25587
|
+
**************************************************************************/
|
|
25588
|
+
set filterContext(value) {
|
|
25589
|
+
this._filterContext = value instanceof FilterContext ? value : null;
|
|
25590
|
+
}
|
|
25591
|
+
get filterContext() {
|
|
25592
|
+
return this._filterContext;
|
|
25593
|
+
}
|
|
25594
|
+
/**
|
|
25595
|
+
* Forced filters are always merged into the final FilterContext.
|
|
25596
|
+
*
|
|
25597
|
+
* This means they override user defined filters, but attempt
|
|
25598
|
+
* to also keep the users intent (by merging) them.
|
|
25599
|
+
*/
|
|
25600
|
+
set forcedFilters(filters) {
|
|
25601
|
+
this.forcedFilters$.next(filters);
|
|
25602
|
+
}
|
|
25603
|
+
get forcedFilters() {
|
|
25604
|
+
return this.forcedFilters$.getValue();
|
|
25605
|
+
}
|
|
25606
|
+
set startFilters(filters) {
|
|
25607
|
+
this.startFilters$.next(filters);
|
|
25608
|
+
}
|
|
25609
|
+
get attributes() {
|
|
25610
|
+
return this._searchInputs.asObservable();
|
|
25611
|
+
}
|
|
25612
|
+
get attributesSnapshot() {
|
|
25613
|
+
return this._searchInputs.getValue();
|
|
25614
|
+
}
|
|
25615
|
+
get states$() {
|
|
25616
|
+
return this._searchStates.asObservable();
|
|
25617
|
+
}
|
|
25618
|
+
get statesSnapshot() {
|
|
25619
|
+
return this._searchStates.getValue();
|
|
25620
|
+
}
|
|
25621
|
+
/**
|
|
25622
|
+
* Returns the current user touched attributes. (ignoring fallbacks)
|
|
25623
|
+
*/
|
|
25624
|
+
get userDefinedAttributes$() {
|
|
25625
|
+
return this.states$.pipe(map(states => states.filter(s => !s.pristine)));
|
|
25626
|
+
}
|
|
25627
|
+
/**
|
|
25628
|
+
* Returns the current active filters
|
|
25629
|
+
*/
|
|
25630
|
+
get filters$() {
|
|
25631
|
+
return this._filters$.asObservable();
|
|
25632
|
+
}
|
|
25633
|
+
get initialFilters$() {
|
|
25634
|
+
return this._initialFilters$.asObservable();
|
|
25635
|
+
}
|
|
25636
|
+
get filtersSnapshot() {
|
|
25637
|
+
return this._filters$.getValue();
|
|
25638
|
+
}
|
|
25639
|
+
/***************************************************************************
|
|
25640
|
+
* *
|
|
25641
|
+
* Public API *
|
|
25642
|
+
* *
|
|
25643
|
+
**************************************************************************/
|
|
25644
|
+
/**
|
|
25645
|
+
* Register a new search name in this container
|
|
25646
|
+
*/
|
|
25647
|
+
register(searchInput) {
|
|
25648
|
+
this.log.debug("Registering search input [" + searchInput.name + "]");
|
|
25649
|
+
const current = this._searchInputs.getValue();
|
|
25650
|
+
this._searchInputs.next([...current, searchInput]);
|
|
25651
|
+
}
|
|
25652
|
+
reset() {
|
|
25653
|
+
this.attributesSnapshot
|
|
25654
|
+
.filter(attr => !attr.readonly)
|
|
25655
|
+
.forEach(a => {
|
|
25656
|
+
a.reset();
|
|
25657
|
+
});
|
|
25658
|
+
}
|
|
25659
|
+
registerInitialFilters(filters) {
|
|
25660
|
+
this._initialFilters$.next(filters);
|
|
25661
|
+
}
|
|
25662
|
+
/***************************************************************************
|
|
25663
|
+
* *
|
|
25664
|
+
* Private *
|
|
25665
|
+
* *
|
|
25666
|
+
**************************************************************************/
|
|
25667
|
+
subscribeInitialFilters() {
|
|
25668
|
+
this.initialFilters$.pipe(takeUntil(this.destroy$), combineLatestWith(this._searchInputs, this.startFilters$)).subscribe(([initialFilters, searchInputs, startFilters]) => {
|
|
25669
|
+
var filters = [...initialFilters, ...startFilters];
|
|
25670
|
+
searchInputs.forEach(input => input.setInitialFilter(filters));
|
|
25671
|
+
});
|
|
25672
|
+
}
|
|
25673
|
+
convertToFilters(states) {
|
|
25674
|
+
return states
|
|
25675
|
+
.map(s => new Filter(s.queryKey, s.queryValue));
|
|
25676
|
+
}
|
|
25677
|
+
applyFilters(userFilters, forcedFilters) {
|
|
25678
|
+
const context = this.filterContext;
|
|
25679
|
+
if (context) {
|
|
25680
|
+
context.updateFilters(userFilters);
|
|
25681
|
+
context.mergeFilters(forcedFilters);
|
|
25682
|
+
this.log.trace("Search-Model filters updated:", Array.from(context.filtersSnapshot));
|
|
25683
|
+
}
|
|
25684
|
+
}
|
|
25685
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
25686
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.9", type: ElderSearchContextDirective, selector: "[elderSearchContext]", inputs: { filterContext: ["elderSearchContext", "filterContext"], forcedFilters: "forcedFilters", startFilters: "startFilters" }, exportAs: ["elderSearchContext"], ngImport: i0 }); }
|
|
25687
|
+
}
|
|
25688
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchContextDirective, decorators: [{
|
|
25689
|
+
type: Directive,
|
|
25690
|
+
args: [{
|
|
25691
|
+
selector: "[elderSearchContext]",
|
|
25692
|
+
exportAs: "elderSearchContext"
|
|
25693
|
+
}]
|
|
25694
|
+
}], propDecorators: { filterContext: [{
|
|
25695
|
+
type: Input,
|
|
25696
|
+
args: ["elderSearchContext"]
|
|
25697
|
+
}], forcedFilters: [{
|
|
25698
|
+
type: Input
|
|
25699
|
+
}], startFilters: [{
|
|
25700
|
+
type: Input
|
|
25701
|
+
}] } });
|
|
25702
|
+
|
|
25521
25703
|
/**
|
|
25522
25704
|
* Immutable representation of the state of an search input
|
|
25523
25705
|
*/
|
|
@@ -25599,8 +25781,19 @@ class SearchInputState {
|
|
|
25599
25781
|
* Search name adapter for input controls.
|
|
25600
25782
|
*/
|
|
25601
25783
|
class ElderInitialValueDirective {
|
|
25784
|
+
/***************************************************************************
|
|
25785
|
+
* *
|
|
25786
|
+
* Constructor *
|
|
25787
|
+
* *
|
|
25788
|
+
**************************************************************************/
|
|
25602
25789
|
constructor(ngModel) {
|
|
25603
25790
|
this.ngModel = ngModel;
|
|
25791
|
+
/***************************************************************************
|
|
25792
|
+
* *
|
|
25793
|
+
* Fields *
|
|
25794
|
+
* *
|
|
25795
|
+
**************************************************************************/
|
|
25796
|
+
this.log = LoggerFactory.getLogger(this.constructor.name);
|
|
25604
25797
|
this.newValue$ = new BehaviorSubject(null);
|
|
25605
25798
|
this.unsubscribe$ = new Subject();
|
|
25606
25799
|
this.initialDone$ = new Subject();
|
|
@@ -25614,8 +25807,16 @@ class ElderInitialValueDirective {
|
|
|
25614
25807
|
this.initialDone$.complete();
|
|
25615
25808
|
ngModel.control.setValue(newValue ? newValue : value);
|
|
25616
25809
|
}
|
|
25810
|
+
else {
|
|
25811
|
+
this.log.warn('Initialisation not yet done! initialValue = ' + this.initialValue + '. Current Val: ', value);
|
|
25812
|
+
}
|
|
25617
25813
|
});
|
|
25618
25814
|
}
|
|
25815
|
+
/***************************************************************************
|
|
25816
|
+
* *
|
|
25817
|
+
* Properties *
|
|
25818
|
+
* *
|
|
25819
|
+
**************************************************************************/
|
|
25619
25820
|
get valueChanges$() {
|
|
25620
25821
|
return this.ngModel.control.valueChanges
|
|
25621
25822
|
.pipe(skipUntil(this.initialDone$), filter$1(value => this.filterInitialValue(value)));
|
|
@@ -25627,6 +25828,11 @@ class ElderInitialValueDirective {
|
|
|
25627
25828
|
this.unsubscribe$.next();
|
|
25628
25829
|
this.unsubscribe$.complete();
|
|
25629
25830
|
}
|
|
25831
|
+
/***************************************************************************
|
|
25832
|
+
* *
|
|
25833
|
+
* Private methods *
|
|
25834
|
+
* *
|
|
25835
|
+
**************************************************************************/
|
|
25630
25836
|
filterInitialValue(value) {
|
|
25631
25837
|
if (this.isInitial && this.initialValue === value) {
|
|
25632
25838
|
this.isInitial = false;
|
|
@@ -25656,14 +25862,13 @@ class ElderSearchInputDirective {
|
|
|
25656
25862
|
* Constructor *
|
|
25657
25863
|
* *
|
|
25658
25864
|
**************************************************************************/
|
|
25659
|
-
constructor(searchContext,
|
|
25865
|
+
constructor(searchContext, ngModel) {
|
|
25660
25866
|
this.searchContext = searchContext;
|
|
25661
|
-
this.changeDetection = changeDetection;
|
|
25662
25867
|
this.ngModel = ngModel;
|
|
25663
25868
|
//TODO: In Angular 16, use standalone directives and host component to inject directive to component
|
|
25664
25869
|
this.initialValueDirective = new ElderInitialValueDirective(this.ngModel);
|
|
25665
25870
|
this._state = new BehaviorSubject(null);
|
|
25666
|
-
this.
|
|
25871
|
+
this.destroy$ = new Subject();
|
|
25667
25872
|
this.log = LoggerFactory.getLogger(this.constructor.name);
|
|
25668
25873
|
}
|
|
25669
25874
|
/***************************************************************************
|
|
@@ -25673,14 +25878,15 @@ class ElderSearchInputDirective {
|
|
|
25673
25878
|
**************************************************************************/
|
|
25674
25879
|
ngAfterViewInit() {
|
|
25675
25880
|
this._extractedName = this.extractName();
|
|
25676
|
-
|
|
25881
|
+
this.log.debug(this.extractName() + "|" + this.queryKey + "|" + this.resolvePath);
|
|
25882
|
+
this.searchContext.register(this);
|
|
25677
25883
|
this.stateObservable().subscribe(state => {
|
|
25678
25884
|
this.emitState(state);
|
|
25679
25885
|
});
|
|
25680
25886
|
}
|
|
25681
25887
|
ngOnDestroy() {
|
|
25682
|
-
this.
|
|
25683
|
-
this.
|
|
25888
|
+
this.destroy$.next();
|
|
25889
|
+
this.destroy$.complete();
|
|
25684
25890
|
}
|
|
25685
25891
|
/***************************************************************************
|
|
25686
25892
|
* *
|
|
@@ -25741,7 +25947,7 @@ class ElderSearchInputDirective {
|
|
|
25741
25947
|
return null;
|
|
25742
25948
|
}
|
|
25743
25949
|
stateObservable() {
|
|
25744
|
-
return this.initialValueDirective.valueChanges$.pipe(takeUntil(this.
|
|
25950
|
+
return this.initialValueDirective.valueChanges$.pipe(takeUntil(this.destroy$), map(value => {
|
|
25745
25951
|
const queryValue = this.convertRawModelValueToQueryString(value);
|
|
25746
25952
|
const pristine = !this.isAttributeValuePresent(value);
|
|
25747
25953
|
return new SearchInputState(this.name, queryValue, this.queryKey || this.name, pristine);
|
|
@@ -25843,7 +26049,7 @@ class ElderSearchInputDirective {
|
|
|
25843
26049
|
});
|
|
25844
26050
|
return CollectionUtil.flatten(arrays);
|
|
25845
26051
|
}
|
|
25846
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchInputDirective, deps: [{ token: ElderSearchContextDirective }, { token:
|
|
26052
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchInputDirective, deps: [{ token: ElderSearchContextDirective }, { token: i3.NgModel, host: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
25847
26053
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.9", type: ElderSearchInputDirective, selector: "[elderSearchInput]", inputs: { queryKey: ["elderSearchInputKey", "queryKey"], valueTransform: ["elderSearchInputTransform", "valueTransform"], resolvePath: ["elderSearchInput", "resolvePath"], dataSource: "dataSource", fallbackValue: ["elderSearchInputFallback", "fallbackValue"], valueAsId: "valueAsId" }, exportAs: ["elderSearchInput"], ngImport: i0 }); }
|
|
25848
26054
|
}
|
|
25849
26055
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchInputDirective, decorators: [{
|
|
@@ -25852,7 +26058,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImpor
|
|
|
25852
26058
|
selector: "[elderSearchInput]",
|
|
25853
26059
|
exportAs: "elderSearchInput"
|
|
25854
26060
|
}]
|
|
25855
|
-
}], ctorParameters: function () { return [{ type: ElderSearchContextDirective }, { type:
|
|
26061
|
+
}], ctorParameters: function () { return [{ type: ElderSearchContextDirective }, { type: i3.NgModel, decorators: [{
|
|
25856
26062
|
type: Host
|
|
25857
26063
|
}] }]; }, propDecorators: { queryKey: [{
|
|
25858
26064
|
type: Input,
|
|
@@ -25874,191 +26080,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImpor
|
|
|
25874
26080
|
args: ["valueAsId"]
|
|
25875
26081
|
}] } });
|
|
25876
26082
|
|
|
25877
|
-
/**
|
|
25878
|
-
* The search container manages a group of search-inputs
|
|
25879
|
-
* and holds their values in a central search model.
|
|
25880
|
-
*/
|
|
25881
|
-
class ElderSearchContextDirective {
|
|
25882
|
-
/***************************************************************************
|
|
25883
|
-
* *
|
|
25884
|
-
* Constructor *
|
|
25885
|
-
* *
|
|
25886
|
-
**************************************************************************/
|
|
25887
|
-
constructor(parentContext) {
|
|
25888
|
-
this.parentContext = parentContext;
|
|
25889
|
-
this.childSearchInputs$ = new BehaviorSubject$1([]);
|
|
25890
|
-
this.forcedFilters$ = new BehaviorSubject$1([]);
|
|
25891
|
-
this.log = LoggerFactory.getLogger(this.constructor.name);
|
|
25892
|
-
this._unsubscribe$ = new Subject$1();
|
|
25893
|
-
this._searchStates = new BehaviorSubject$1([]);
|
|
25894
|
-
this._filters$ = new BehaviorSubject$1([]);
|
|
25895
|
-
this._initialFilters$ = new BehaviorSubject$1([]);
|
|
25896
|
-
}
|
|
25897
|
-
/***************************************************************************
|
|
25898
|
-
* *
|
|
25899
|
-
* Life Cycle *
|
|
25900
|
-
* *
|
|
25901
|
-
**************************************************************************/
|
|
25902
|
-
ngAfterContentInit() {
|
|
25903
|
-
if (!this.isParentContextNull()) {
|
|
25904
|
-
this.registerInputsToParentContext();
|
|
25905
|
-
}
|
|
25906
|
-
}
|
|
25907
|
-
ngAfterViewInit() {
|
|
25908
|
-
if (this.isParentContextNull()) {
|
|
25909
|
-
this.subscribeSearchInputs();
|
|
25910
|
-
this.subscribeInitialFilters();
|
|
25911
|
-
}
|
|
25912
|
-
}
|
|
25913
|
-
ngOnDestroy() {
|
|
25914
|
-
this._unsubscribe$.next();
|
|
25915
|
-
this._unsubscribe$.complete();
|
|
25916
|
-
}
|
|
25917
|
-
/***************************************************************************
|
|
25918
|
-
* *
|
|
25919
|
-
* Properties *
|
|
25920
|
-
* *
|
|
25921
|
-
**************************************************************************/
|
|
25922
|
-
set filterContext(value) {
|
|
25923
|
-
this._filterContext = value instanceof FilterContext ? value : null;
|
|
25924
|
-
}
|
|
25925
|
-
get filterContext() {
|
|
25926
|
-
return this._filterContext;
|
|
25927
|
-
}
|
|
25928
|
-
/**
|
|
25929
|
-
* Forced filters are always merged into the final FilterContext.
|
|
25930
|
-
*
|
|
25931
|
-
* This means they override user defined filters, but attempt
|
|
25932
|
-
* to also keep the users intent (by merging) them.
|
|
25933
|
-
*/
|
|
25934
|
-
set forcedFilters(filters) {
|
|
25935
|
-
this.forcedFilters$.next(filters);
|
|
25936
|
-
}
|
|
25937
|
-
get forcedFilters() {
|
|
25938
|
-
return this.forcedFilters$.getValue();
|
|
25939
|
-
}
|
|
25940
|
-
get attributes() {
|
|
25941
|
-
return this.searchInputs.changes.pipe(map(inputs => inputs), map(inputs => inputs.toArray()));
|
|
25942
|
-
}
|
|
25943
|
-
get attributesSnapshot() {
|
|
25944
|
-
return this.zipInputsWithChildInputs(this.searchInputs.toArray(), this.childSearchInputs$.getValue());
|
|
25945
|
-
}
|
|
25946
|
-
get states$() {
|
|
25947
|
-
return this._searchStates.asObservable();
|
|
25948
|
-
}
|
|
25949
|
-
get statesSnapshot() {
|
|
25950
|
-
return this._searchStates.getValue();
|
|
25951
|
-
}
|
|
25952
|
-
/**
|
|
25953
|
-
* Returns the current user touched attributes. (ignoring fallbacks)
|
|
25954
|
-
*/
|
|
25955
|
-
get userDefinedAttributes$() {
|
|
25956
|
-
return this.states$.pipe(map(states => states.filter(s => !s.pristine)));
|
|
25957
|
-
}
|
|
25958
|
-
/**
|
|
25959
|
-
* Returns the current active filters
|
|
25960
|
-
*/
|
|
25961
|
-
get filters$() {
|
|
25962
|
-
return this._filters$.asObservable();
|
|
25963
|
-
}
|
|
25964
|
-
get initialFilters$() {
|
|
25965
|
-
return this._initialFilters$.asObservable();
|
|
25966
|
-
}
|
|
25967
|
-
get filtersSnapshot() {
|
|
25968
|
-
return this._filters$.getValue();
|
|
25969
|
-
}
|
|
25970
|
-
/***************************************************************************
|
|
25971
|
-
* *
|
|
25972
|
-
* Public API *
|
|
25973
|
-
* *
|
|
25974
|
-
**************************************************************************/
|
|
25975
|
-
registerInput(searchInputs) {
|
|
25976
|
-
this.childSearchInputs$.next([...this.childSearchInputs$.getValue(), ...searchInputs]);
|
|
25977
|
-
}
|
|
25978
|
-
registerInitialFilters(filters) {
|
|
25979
|
-
this._initialFilters$.next(filters);
|
|
25980
|
-
}
|
|
25981
|
-
reset() {
|
|
25982
|
-
if (this.isParentContextNull()) {
|
|
25983
|
-
this.resetInputs();
|
|
25984
|
-
}
|
|
25985
|
-
else {
|
|
25986
|
-
this.parentContext.reset();
|
|
25987
|
-
}
|
|
25988
|
-
}
|
|
25989
|
-
/***************************************************************************
|
|
25990
|
-
* *
|
|
25991
|
-
* Private *
|
|
25992
|
-
* *
|
|
25993
|
-
**************************************************************************/
|
|
25994
|
-
resetInputs() {
|
|
25995
|
-
this.attributesSnapshot
|
|
25996
|
-
.filter(attr => !attr.readonly)
|
|
25997
|
-
.forEach(a => {
|
|
25998
|
-
a.reset();
|
|
25999
|
-
});
|
|
26000
|
-
}
|
|
26001
|
-
registerInputsToParentContext() {
|
|
26002
|
-
if (!this.isParentContextNull()) {
|
|
26003
|
-
this.parentContext.registerInput(this.searchInputs.toArray());
|
|
26004
|
-
}
|
|
26005
|
-
}
|
|
26006
|
-
isParentContextNull() {
|
|
26007
|
-
return this.parentContext === null;
|
|
26008
|
-
}
|
|
26009
|
-
subscribeSearchInputs() {
|
|
26010
|
-
this.searchInputs.changes
|
|
26011
|
-
.pipe(startWith(this.searchInputs), takeUntil(this._unsubscribe$), map(input => input), combineLatestWith(this.childSearchInputs$), map(([inputs, childInputs]) => this.zipInputsWithChildInputs(inputs.toArray(), childInputs)), switchMap(inputs => combineLatest(inputs.map(i => i.state$))), combineLatestWith(this.forcedFilters$), debounceTime(5)).subscribe(([states, forcedFilters]) => {
|
|
26012
|
-
this._searchStates.next(states);
|
|
26013
|
-
const userFilters = this.convertToFilters(states);
|
|
26014
|
-
this._filters$.next(userFilters);
|
|
26015
|
-
this.applyFilters(userFilters, forcedFilters);
|
|
26016
|
-
});
|
|
26017
|
-
}
|
|
26018
|
-
zipInputsWithChildInputs(inputs, childInputs) {
|
|
26019
|
-
return [...inputs, ...childInputs];
|
|
26020
|
-
}
|
|
26021
|
-
subscribeInitialFilters() {
|
|
26022
|
-
this.initialFilters$.pipe(takeUntil(this._unsubscribe$), combineLatestWith(this.childSearchInputs$), skip(1)).subscribe(([initialFilters, childSearchInputs]) => {
|
|
26023
|
-
var searchInputs = this.zipInputsWithChildInputs(this.searchInputs.toArray(), childSearchInputs);
|
|
26024
|
-
searchInputs.forEach(input => input.setInitialFilter(initialFilters));
|
|
26025
|
-
});
|
|
26026
|
-
}
|
|
26027
|
-
convertToFilters(states) {
|
|
26028
|
-
return states
|
|
26029
|
-
.map(s => new Filter(s.queryKey, s.queryValue));
|
|
26030
|
-
}
|
|
26031
|
-
applyFilters(userFilters, forcedFilters) {
|
|
26032
|
-
const context = this.filterContext;
|
|
26033
|
-
if (context) {
|
|
26034
|
-
context.updateFilters(userFilters);
|
|
26035
|
-
context.mergeFilters(forcedFilters);
|
|
26036
|
-
this.log.trace("Search-Model filters updated:", Array.from(context.filtersSnapshot));
|
|
26037
|
-
}
|
|
26038
|
-
}
|
|
26039
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchContextDirective, deps: [{ token: ElderSearchContextDirective, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
26040
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.9", type: ElderSearchContextDirective, selector: "[elderSearchContext]", inputs: { filterContext: ["elderSearchContext", "filterContext"], forcedFilters: "forcedFilters" }, queries: [{ propertyName: "searchInputs", predicate: ElderSearchInputDirective, descendants: true }], exportAs: ["elderSearchContext"], ngImport: i0 }); }
|
|
26041
|
-
}
|
|
26042
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchContextDirective, decorators: [{
|
|
26043
|
-
type: Directive,
|
|
26044
|
-
args: [{
|
|
26045
|
-
selector: "[elderSearchContext]",
|
|
26046
|
-
exportAs: "elderSearchContext"
|
|
26047
|
-
}]
|
|
26048
|
-
}], ctorParameters: function () { return [{ type: ElderSearchContextDirective, decorators: [{
|
|
26049
|
-
type: SkipSelf
|
|
26050
|
-
}, {
|
|
26051
|
-
type: Optional
|
|
26052
|
-
}] }]; }, propDecorators: { searchInputs: [{
|
|
26053
|
-
type: ContentChildren,
|
|
26054
|
-
args: [ElderSearchInputDirective, { descendants: true }]
|
|
26055
|
-
}], filterContext: [{
|
|
26056
|
-
type: Input,
|
|
26057
|
-
args: ["elderSearchContext"]
|
|
26058
|
-
}], forcedFilters: [{
|
|
26059
|
-
type: Input
|
|
26060
|
-
}] } });
|
|
26061
|
-
|
|
26062
26083
|
class ElderSearchPanelComponent {
|
|
26063
26084
|
constructor() { }
|
|
26064
26085
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -26452,11 +26473,11 @@ class ElderSearchBoxComponent {
|
|
|
26452
26473
|
this.searchModel.reset();
|
|
26453
26474
|
}
|
|
26454
26475
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchBoxComponent, deps: [{ token: ElderSearchContextDirective }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26455
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.9", type: ElderSearchBoxComponent, selector: "elder-search-box", inputs: { autoPanel: "autoPanel", name: "name", queryKey: "queryKey", placeholder: "placeholder", label: "label", hint: "hint", autocomplete: "autocomplete", appearance: "appearance", dense: "dense" }, host: { classAttribute: "elder-form-field-host" }, queries: [{ propertyName: "advancedSearch", first: true, predicate: ElderSearchPanelComponent, descendants: true }], viewQueries: [{ propertyName: "search", first: true, predicate: ["search"], descendants: true }], exportAs: ["elderSearchBox"], ngImport: i0, template: "<div class=\"layout-row place-stretch-center full flex\" style=\"overflow: hidden\"
|
|
26476
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.9", type: ElderSearchBoxComponent, selector: "elder-search-box", inputs: { autoPanel: "autoPanel", name: "name", queryKey: "queryKey", placeholder: "placeholder", label: "label", hint: "hint", autocomplete: "autocomplete", appearance: "appearance", dense: "dense" }, host: { classAttribute: "elder-form-field-host" }, queries: [{ propertyName: "advancedSearch", first: true, predicate: ElderSearchPanelComponent, descendants: true }], viewQueries: [{ propertyName: "search", first: true, predicate: ["search"], descendants: true }], exportAs: ["elderSearchBox"], ngImport: i0, template: "<div class=\"layout-row place-stretch-center full flex\" style=\"overflow: hidden\">\n <mat-form-field\n *ngIf=\"overlayState$ | async as overlayState\"\n [appearance]=\"appearance\"\n class=\"elder-search-box-field flex-auto\" subscriptSizing=\"dynamic\"\n [elderDense]=\"dense\">\n\n <button matPrefix mat-icon-button type=\"button\"\n [elderOverlayTrigger]=\"searchPanel\" (click)=\"blurFocus($event)\"\n >\n <mat-icon>search</mat-icon>\n </button>\n\n <input matInput type=\"text\" [name]=\"name\" [placeholder]=\"placeholder\" #search cdkFocusInitial\n ngModel\n elderSearchInput [elderSearchInputKey]=\"queryKey\" #searchInput=\"elderSearchInput\"\n [autocomplete]=\"(autoPanel && overlayState.hasOverlay) ? 'off' : autocomplete\"\n [elderOverlayOrigin]=\"searchPanel\"\n [elderOverlayTrigger]=\"searchPanel\"\n [elderOverlayTriggerType]=\"'focus'\"\n [elderOverlayTriggerEnabled]=\"autoPanel && overlayState.hasOverlay && (searchInput?.state$ | async)?.pristine\"\n >\n <mat-hint *ngIf=\"hint\">{{hint}}</mat-hint>\n\n <div class=\"layout-row\" matSuffix *ngIf=\"searchModel.userDefinedAttributes$ | async as userDefinedFilters\">\n\n <button mat-icon-button type=\"button\"\n *ngIf=\"userDefinedFilters.length > 0\"\n (click)=\"clearSearch($event)\"\n name=\"clear\" aria-label=\"Clear\">\n <mat-icon>close</mat-icon>\n </button>\n\n <button mat-icon-button type=\"button\"\n *ngIf=\"overlayState.hasOverlay\" name=\"openPanel\"\n [elderOverlayTrigger]=\"searchPanel\" (click)=\"blurFocus($event)\">\n <mat-icon\n [matBadge]=\"userDefinedFilters.length\"\n matBadgeSize=\"small\"\n [matBadgeOverlap]=\"true\"\n [matBadgeHidden]=\"userDefinedFilters.length == 0\"\n matBadgeColor=\"accent\"\n [color]=\"userDefinedFilters.length > 0 ? 'accent' : undefined\"\n >\n filter_list\n </mat-icon>\n </button>\n </div>\n </mat-form-field>\n</div>\n\n\n<!-- Overlay Panel for advanced search -->\n<elder-overlay #searchPanel=\"elderOverlay\">\n <elder-dialog-panel class=\"elder-search-panel-container\">\n\n <!-- Project the users search inputs here -->\n <ng-content select=\"elder-search-panel\"></ng-content>\n\n <div class=\"layout-row place-between-center\">\n <button mat-raised-button type=\"button\" name=\"clear\"\n (click)=\"clearSearch($event)\">{{'context.reset' | translate}}\n </button>\n\n <button mat-raised-button type=\"button\" name=\"ok\" color=\"primary\"\n (click)=\"searchPanel.closeOverlay()\">Ok\n </button>\n </div>\n </elder-dialog-panel>\n</elder-overlay>\n", styles: [".elder-search-box-field{margin-top:4px;margin-bottom:4px}.elder-search-panel-container{min-width:250px}\n"], dependencies: [{ kind: "directive", type: i1$4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4$3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i5$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i5$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i2$3.MatBadge, selector: "[matBadge]", inputs: ["matBadgeDisabled", "matBadgeColor", "matBadgeOverlap", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: ElderOverlayComponent, selector: "elder-overlay", inputs: ["originX", "originY", "overlayX", "overlayY", "offsetY", "offsetX", "backdrop", "backdropVisible", "origin", "positionStrategy", "overlaySize"], outputs: ["keydownEvents", "attachedChange"], exportAs: ["elderOverlay"] }, { kind: "directive", type: ElderOverlayTriggerDirective, selector: "[elderOverlayTrigger]", inputs: ["elderOverlayTrigger", "elderOverlayTriggerType", "elderOverlayTriggerEnabled"] }, { kind: "directive", type: ElderOverlayOriginDirective, selector: "[elderOverlayOrigin]", inputs: ["elderOverlayOrigin"] }, { kind: "component", type: ElderDialogPanelComponent, selector: "elder-dialog-panel" }, { kind: "directive", type: ElderFormFieldDenseDirective, selector: "mat-form-field[elderDense]", inputs: ["elderDense", "subscriptSizing", "floatLabel"] }, { kind: "directive", type: ElderSearchInputDirective, selector: "[elderSearchInput]", inputs: ["elderSearchInputKey", "elderSearchInputTransform", "elderSearchInput", "dataSource", "elderSearchInputFallback", "valueAsId"], exportAs: ["elderSearchInput"] }, { kind: "pipe", type: i1$4.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
26456
26477
|
}
|
|
26457
26478
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: ElderSearchBoxComponent, decorators: [{
|
|
26458
26479
|
type: Component,
|
|
26459
|
-
args: [{ selector: 'elder-search-box', exportAs: 'elderSearchBox', host: { 'class': 'elder-form-field-host' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"layout-row place-stretch-center full flex\" style=\"overflow: hidden\"
|
|
26480
|
+
args: [{ selector: 'elder-search-box', exportAs: 'elderSearchBox', host: { 'class': 'elder-form-field-host' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"layout-row place-stretch-center full flex\" style=\"overflow: hidden\">\n <mat-form-field\n *ngIf=\"overlayState$ | async as overlayState\"\n [appearance]=\"appearance\"\n class=\"elder-search-box-field flex-auto\" subscriptSizing=\"dynamic\"\n [elderDense]=\"dense\">\n\n <button matPrefix mat-icon-button type=\"button\"\n [elderOverlayTrigger]=\"searchPanel\" (click)=\"blurFocus($event)\"\n >\n <mat-icon>search</mat-icon>\n </button>\n\n <input matInput type=\"text\" [name]=\"name\" [placeholder]=\"placeholder\" #search cdkFocusInitial\n ngModel\n elderSearchInput [elderSearchInputKey]=\"queryKey\" #searchInput=\"elderSearchInput\"\n [autocomplete]=\"(autoPanel && overlayState.hasOverlay) ? 'off' : autocomplete\"\n [elderOverlayOrigin]=\"searchPanel\"\n [elderOverlayTrigger]=\"searchPanel\"\n [elderOverlayTriggerType]=\"'focus'\"\n [elderOverlayTriggerEnabled]=\"autoPanel && overlayState.hasOverlay && (searchInput?.state$ | async)?.pristine\"\n >\n <mat-hint *ngIf=\"hint\">{{hint}}</mat-hint>\n\n <div class=\"layout-row\" matSuffix *ngIf=\"searchModel.userDefinedAttributes$ | async as userDefinedFilters\">\n\n <button mat-icon-button type=\"button\"\n *ngIf=\"userDefinedFilters.length > 0\"\n (click)=\"clearSearch($event)\"\n name=\"clear\" aria-label=\"Clear\">\n <mat-icon>close</mat-icon>\n </button>\n\n <button mat-icon-button type=\"button\"\n *ngIf=\"overlayState.hasOverlay\" name=\"openPanel\"\n [elderOverlayTrigger]=\"searchPanel\" (click)=\"blurFocus($event)\">\n <mat-icon\n [matBadge]=\"userDefinedFilters.length\"\n matBadgeSize=\"small\"\n [matBadgeOverlap]=\"true\"\n [matBadgeHidden]=\"userDefinedFilters.length == 0\"\n matBadgeColor=\"accent\"\n [color]=\"userDefinedFilters.length > 0 ? 'accent' : undefined\"\n >\n filter_list\n </mat-icon>\n </button>\n </div>\n </mat-form-field>\n</div>\n\n\n<!-- Overlay Panel for advanced search -->\n<elder-overlay #searchPanel=\"elderOverlay\">\n <elder-dialog-panel class=\"elder-search-panel-container\">\n\n <!-- Project the users search inputs here -->\n <ng-content select=\"elder-search-panel\"></ng-content>\n\n <div class=\"layout-row place-between-center\">\n <button mat-raised-button type=\"button\" name=\"clear\"\n (click)=\"clearSearch($event)\">{{'context.reset' | translate}}\n </button>\n\n <button mat-raised-button type=\"button\" name=\"ok\" color=\"primary\"\n (click)=\"searchPanel.closeOverlay()\">Ok\n </button>\n </div>\n </elder-dialog-panel>\n</elder-overlay>\n", styles: [".elder-search-box-field{margin-top:4px;margin-bottom:4px}.elder-search-panel-container{min-width:250px}\n"] }]
|
|
26460
26481
|
}], ctorParameters: function () { return [{ type: ElderSearchContextDirective }]; }, propDecorators: { search: [{
|
|
26461
26482
|
type: ViewChild,
|
|
26462
26483
|
args: ['search']
|
|
@@ -26682,8 +26703,7 @@ class ElderSearchContextUrlBindingDirective {
|
|
|
26682
26703
|
this.urlBindingService.initialSearchMap$.pipe(first(), takeUntil(this._unsubscribe$), filter(searchMap => searchMap.has(this._urlBinding)), map(searchMap => searchMap.get(this._urlBinding)), map(filterMap => Array.from(filterMap.filters.values()))).subscribe(filters => {
|
|
26683
26704
|
this.searchContext.registerInitialFilters(filters);
|
|
26684
26705
|
});
|
|
26685
|
-
this.searchContext.filters$.pipe(takeUntil(this._unsubscribe$)
|
|
26686
|
-
).subscribe(filters => this.urlBindingService.updateFiltersForContext(this._urlBinding, filters));
|
|
26706
|
+
this.searchContext.filters$.pipe(takeUntil(this._unsubscribe$)).subscribe(filters => this.urlBindingService.updateFiltersForContext(this._urlBinding, filters));
|
|
26687
26707
|
}
|
|
26688
26708
|
ngOnDestroy() {
|
|
26689
26709
|
this._unsubscribe$.next();
|