diff --git a/src/app/core/shared/search/search-filter.service.spec.ts b/src/app/core/shared/search/search-filter.service.spec.ts index 435e452549b..09269ee720e 100644 --- a/src/app/core/shared/search/search-filter.service.spec.ts +++ b/src/app/core/shared/search/search-filter.service.spec.ts @@ -153,17 +153,6 @@ describe('SearchFilterService', () => { }); }); - describe('when the getSelectedValuesForFilter method is called', () => { - beforeEach(() => { - spyOn(routeServiceStub, 'getQueryParameterValues'); - service.getSelectedValuesForFilter(mockFilterConfig); - }); - - it('should call getQueryParameterValues on the route service with the same parameters', () => { - expect(routeServiceStub.getQueryParameterValues).toHaveBeenCalledWith(mockFilterConfig.paramName); - }); - }); - describe('when the getCurrentScope method is called', () => { beforeEach(() => { spyOn(routeServiceStub, 'getQueryParameterValue'); diff --git a/src/app/core/shared/search/search-filter.service.ts b/src/app/core/shared/search/search-filter.service.ts index c4675be50f1..cfed6fe41e6 100644 --- a/src/app/core/shared/search/search-filter.service.ts +++ b/src/app/core/shared/search/search-filter.service.ts @@ -136,27 +136,6 @@ export class SearchFilterService { return this.routeService.getQueryParameterValue('view'); } - /** - * Requests the active filter values set for a given filter - * @param {SearchFilterConfig} filterConfig The configuration for which the filters are active - * @returns {Observable} Emits the active filters for the given filter configuration - */ - getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable { - const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName); - const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').pipe( - map((params: Params) => [].concat(...Object.values(params))), - ); - return observableCombineLatest(values$, prefixValues$).pipe( - map(([values, prefixValues]) => { - if (isNotEmpty(values)) { - return values; - } - return prefixValues; - } - ) - ); - } - /** * Updates the found facet value suggestions for a given query * Transforms the found values into display values diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts index 0a69fbd667d..7093822c9b2 100644 --- a/src/app/core/shared/search/search.service.ts +++ b/src/app/core/shared/search/search.service.ts @@ -1,7 +1,7 @@ /* eslint-disable max-classes-per-file */ import { combineLatest as observableCombineLatest, Observable, BehaviorSubject } from 'rxjs'; -import { Injectable, OnDestroy } from '@angular/core'; -import { map, switchMap, take, tap } from 'rxjs/operators'; +import { Injectable } from '@angular/core'; +import { map, switchMap, take, tap, distinctUntilChanged } from 'rxjs/operators'; import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; import { ResponseParsingService } from '../../data/parsing.service'; import { RemoteData } from '../../data/remote-data'; @@ -61,7 +61,7 @@ class SearchDataService extends BaseDataService { * Service that performs all general actions that have to do with the search page */ @Injectable() -export class SearchService implements OnDestroy { +export class SearchService { /** * Endpoint link path for retrieving general search results @@ -78,11 +78,6 @@ export class SearchService implements OnDestroy { */ private request: GenericConstructor = GetRequest; - /** - * Subscription to unsubscribe from - */ - private sub; - /** * Instance of SearchDataService to forward data service methods to */ @@ -103,6 +98,18 @@ export class SearchService implements OnDestroy { this.searchDataService = new SearchDataService(); } + /** + * Get the currently {@link AppliedFilter}s for the given filter. + * + * @param filterName The name of the filter + */ + getSelectedValuesForFilter(filterName: string): Observable { + return this.appliedFilters$.pipe( + map((appliedFilters: AppliedFilter[]) => appliedFilters.filter((appliedFilter: AppliedFilter) => appliedFilter.filter === filterName)), + distinctUntilChanged((previous: AppliedFilter[], next: AppliedFilter[]) => JSON.stringify(previous) === JSON.stringify(next)), + ); + } + /** * Method to set service options * @param {GenericConstructor} parser The ResponseParsingService constructor name @@ -176,26 +183,11 @@ export class SearchService implements OnDestroy { return this.directlyAttachIndexableObjects(sqr$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } - /** - * Method to retrieve request entries for search results from the server - * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search - * @returns {Observable>>} Emits a paginated list with all search results found - */ - searchEntries(searchOptions?: PaginatedSearchOptions): Observable>> { - const href$ = this.getEndpoint(searchOptions); - - const sqr$ = href$.pipe( - switchMap((href: string) => this.rdb.buildFromHref>(href)) - ); - - return this.directlyAttachIndexableObjects(sqr$); - } - /** * Method to directly attach the indexableObjects to search results, instead of using RemoteData. * For compatibility with the way the search was written originally * - * @param sqr$: a SearchObjects RemotaData Observable without its + * @param sqr$ A {@link SearchObjects} {@link RemoteData} Observable without its * indexableObjects attached * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's * no valid cached version. Defaults to true @@ -384,12 +376,4 @@ export class SearchService implements OnDestroy { return '/search'; } - /** - * Unsubscribe from the subscription - */ - ngOnDestroy(): void { - if (this.sub !== undefined) { - this.sub.unsubscribe(); - } - } } diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index 8af3aac7be9..e085d3e6678 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -3,7 +3,7 @@ import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { Router, Params } from '@angular/router'; import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs'; -import { debounceTime, distinctUntilChanged, filter, map, mergeMap, switchMap, take, tap } from 'rxjs/operators'; +import { distinctUntilChanged, map, switchMap, take, tap } from 'rxjs/operators'; import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; import { hasNoValue, hasValue } from '../../../../empty.util'; @@ -17,7 +17,6 @@ import { InputSuggestion } from '../../../../input-suggestions/input-suggestions import { SearchOptions } from '../../../models/search-options.model'; import { SEARCH_CONFIG_SERVICE } from '../../../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../../../utils/route.utils'; -import { stripOperatorFromFilterValue } from '../../../search.utils'; import { FacetValues } from '../../../models/facet-values.model'; import { AppliedFilter } from '../../../models/applied-filter.model'; @@ -103,14 +102,9 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { this.searchOptions$ = this.searchConfigService.searchOptions; this.subs.push( this.searchOptions$.subscribe(() => this.updateFilterValueList()), - this.refreshFilters.asObservable().pipe( - filter((toRefresh: boolean) => toRefresh), - // NOTE This is a workaround, otherwise retrieving filter values returns tha old cached response - debounceTime((100)), - mergeMap(() => this.retrieveFilterValues(false)) - ).subscribe() + this.retrieveFilterValues().subscribe(), ); - this.retrieveFilterValues().subscribe(); + this.selectedAppliedFilters$ = this.searchService.getSelectedValuesForFilter(this.filterConfig.name); } /** @@ -217,9 +211,13 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { } } - protected retrieveFilterValues(useCachedVersionIfAvailable = true): Observable { + /** + * Retrieves all the filter value suggestion pages that need to be displayed in the facet and combines it into one + * list. + */ + protected retrieveFilterValues(): Observable { return observableCombineLatest([this.searchOptions$, this.currentPage]).pipe( - switchMap(([options, page]: [SearchOptions, number]) => this.searchService.getFacetValuesFor(this.filterConfig, page, options, null, useCachedVersionIfAvailable).pipe( + switchMap(([options, page]: [SearchOptions, number]) => this.searchService.getFacetValuesFor(this.filterConfig, page, options).pipe( getFirstSucceededRemoteDataPayload(), tap((facetValues: FacetValues) => { this.isLastPage$.next(hasNoValue(facetValues?.next)); @@ -242,27 +240,12 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { return filterValues; }), tap((allFacetValues: FacetValues[]) => { - this.setAppliedFilter(allFacetValues); this.animationState = 'ready'; this.facetValues$.next(allFacetValues); }) ); } - setAppliedFilter(allFacetValues: FacetValues[]): void { - const allAppliedFilters: AppliedFilter[] = [].concat(...allFacetValues.map((facetValues: FacetValues) => facetValues.appliedFilters)) - .filter((appliedFilter: AppliedFilter) => hasValue(appliedFilter)); - - this.selectedAppliedFilters$ = this.filterService.getSelectedValuesForFilter(this.filterConfig).pipe( - map((selectedValues: string[]) => { - const appliedFilters: AppliedFilter[] = selectedValues.map((value: string) => { - return allAppliedFilters.find((appliedFilter: AppliedFilter) => appliedFilter.value === stripOperatorFromFilterValue(value)); - }).filter((appliedFilter: AppliedFilter) => hasValue(appliedFilter)); - return appliedFilters; - }), - ); - } - /** * Prevent unnecessary rerendering */ diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts index 7abe45ca8c7..3404d3def81 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.spec.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; @@ -14,51 +14,28 @@ import { SearchConfigurationServiceStub } from '../../../testing/search-configur import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component'; import { SequenceService } from '../../../../core/shared/sequence.service'; import { BrowserOnlyMockPipe } from '../../../testing/browser-only-mock.pipe'; +import { SearchServiceStub } from '../../../testing/search-service.stub'; +import { SearchFilterServiceStub } from '../../../testing/search-filter-service.stub'; describe('SearchFilterComponent', () => { let comp: SearchFilterComponent; let fixture: ComponentFixture; const filterName1 = 'test name'; - const filterName2 = 'test2'; - const filterName3 = 'another name3'; - const nonExistingFilter1 = 'non existing 1'; - const nonExistingFilter2 = 'non existing 2'; + const mockFilterConfig: SearchFilterConfig = Object.assign(new SearchFilterConfig(), { name: filterName1, filterType: FilterType.text, hasFacets: false, isOpenByDefault: false }); - const mockFilterService = { - /* eslint-disable no-empty,@typescript-eslint/no-empty-function */ - toggle: (filter) => { - }, - collapse: (filter) => { - }, - expand: (filter) => { - }, - initializeFilter: (filter) => { - }, - getSelectedValuesForFilter: (filter) => { - return observableOf([filterName1, filterName2, filterName3]); - }, - isFilterActive: (filter) => { - return observableOf([filterName1, filterName2, filterName3].indexOf(filter) >= 0); - }, - isCollapsed: (filter) => { - return observableOf(true); - } - /* eslint-enable no-empty, @typescript-eslint/no-empty-function */ - - }; - let filterService; + let searchFilterService: SearchFilterServiceStub; let sequenceService; const mockResults = observableOf(['test', 'data']); - const searchServiceStub = { - getFacetValuesFor: (filter) => mockResults - }; + let searchService: SearchServiceStub; beforeEach(waitForAsync(() => { + searchFilterService = new SearchFilterServiceStub(); + searchService = new SearchServiceStub(); sequenceService = jasmine.createSpyObj('sequenceService', { next: 17 }); TestBed.configureTestingModule({ @@ -68,26 +45,23 @@ describe('SearchFilterComponent', () => { BrowserOnlyMockPipe, ], providers: [ - { provide: SearchService, useValue: searchServiceStub }, - { - provide: SearchFilterService, - useValue: mockFilterService - }, + { provide: SearchService, useValue: searchService }, + { provide: SearchFilterService, useValue: searchFilterService }, { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SequenceService, useValue: sequenceService }, ], - schemas: [NO_ERRORS_SCHEMA] + schemas: [CUSTOM_ELEMENTS_SCHEMA], }).overrideComponent(SearchFilterComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(() => { + spyOn(searchService, 'getFacetValuesFor').and.returnValue(mockResults); fixture = TestBed.createComponent(SearchFilterComponent); comp = fixture.componentInstance; // SearchPageComponent test instance comp.filter = mockFilterConfig; fixture.detectChanges(); - filterService = (comp as any).filterService; }); it('should generate unique IDs', () => { @@ -98,54 +72,30 @@ describe('SearchFilterComponent', () => { describe('when the toggle method is triggered', () => { beforeEach(() => { - spyOn(filterService, 'toggle'); + spyOn(searchFilterService, 'toggle'); comp.toggle(); }); it('should call toggle with the correct filter configuration name', () => { - expect(filterService.toggle).toHaveBeenCalledWith(mockFilterConfig.name); + expect(searchFilterService.toggle).toHaveBeenCalledWith(mockFilterConfig.name); }); }); describe('when the initializeFilter method is triggered', () => { beforeEach(() => { - spyOn(filterService, 'initializeFilter'); + spyOn(searchFilterService, 'initializeFilter'); comp.initializeFilter(); }); it('should call initialCollapse with the correct filter configuration name', () => { - expect(filterService.initializeFilter).toHaveBeenCalledWith(mockFilterConfig); - }); - }); - - describe('when getSelectedValues is called', () => { - let valuesObservable: Observable; - beforeEach(() => { - valuesObservable = (comp as any).getSelectedValues(); - }); - - it('should return an observable containing the existing filters', () => { - const sub = valuesObservable.subscribe((values) => { - expect(values).toContain(filterName1); - expect(values).toContain(filterName2); - expect(values).toContain(filterName3); - }); - sub.unsubscribe(); - }); - - it('should return an observable that does not contain the non-existing filters', () => { - const sub = valuesObservable.subscribe((values) => { - expect(values).not.toContain(nonExistingFilter1); - expect(values).not.toContain(nonExistingFilter2); - }); - sub.unsubscribe(); + expect(searchFilterService.initializeFilter).toHaveBeenCalledWith(mockFilterConfig); }); }); describe('when isCollapsed is called and the filter is collapsed', () => { let isActive: Observable; beforeEach(() => { - filterService.isCollapsed = () => observableOf(true); + searchFilterService.isCollapsed = () => observableOf(true); isActive = (comp as any).isCollapsed(); }); @@ -160,7 +110,7 @@ describe('SearchFilterComponent', () => { describe('when isCollapsed is called and the filter is not collapsed', () => { let isActive: Observable; beforeEach(() => { - filterService.isCollapsed = () => observableOf(false); + searchFilterService.isCollapsed = () => observableOf(false); isActive = (comp as any).isCollapsed(); }); diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index d1d3bd729d4..e595187dc1d 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -1,6 +1,6 @@ -import { Component, Inject, Input, OnInit } from '@angular/core'; +import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; -import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; +import { BehaviorSubject, Observable, of as observableOf, combineLatest, Subscription } from 'rxjs'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; import { SearchFilterConfig } from '../../models/search-filter-config.model'; @@ -11,6 +11,10 @@ import { SearchService } from '../../../../core/shared/search/search.service'; import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component'; import { SequenceService } from '../../../../core/shared/sequence.service'; +import { FacetValues } from '../../models/facet-values.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { AppliedFilter } from '../../models/applied-filter.model'; +import { SearchOptions } from '../../models/search-options.model'; @Component({ selector: 'ds-search-filter', @@ -22,7 +26,7 @@ import { SequenceService } from '../../../../core/shared/sequence.service'; /** * Represents a part of the filter section for a single type of filter */ -export class SearchFilterComponent implements OnInit { +export class SearchFilterComponent implements OnInit, OnDestroy { /** * The filter config for this component */ @@ -61,13 +65,15 @@ export class SearchFilterComponent implements OnInit { /** * Emits all currently selected values for this filter */ - selectedValues$: Observable; + appliedFilters$: Observable; /** * Emits true when the current filter is supposed to be shown */ active$: Observable; + subs: Subscription[] = []; + private readonly sequenceId: number; constructor( @@ -85,15 +91,19 @@ export class SearchFilterComponent implements OnInit { * Else, the filter should initially be collapsed */ ngOnInit() { - this.selectedValues$ = this.getSelectedValues(); + this.appliedFilters$ = this.searchService.getSelectedValuesForFilter(this.filter.name); this.active$ = this.isActive(); this.collapsed$ = this.isCollapsed(); this.initializeFilter(); - this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { + this.subs.push(this.appliedFilters$.pipe(take(1)).subscribe((selectedValues: AppliedFilter[]) => { if (isNotEmpty(selectedValues)) { this.filterService.expand(this.filter.name); } - }); + })); + } + + ngOnDestroy(): void { + this.subs.forEach((sub: Subscription) => sub.unsubscribe()); } /** @@ -118,13 +128,6 @@ export class SearchFilterComponent implements OnInit { this.filterService.initializeFilter(this.filter); } - /** - * @returns {Observable} Emits a list of all values that are currently active for this filter - */ - private getSelectedValues(): Observable { - return this.filterService.getSelectedValuesForFilter(this.filter); - } - /** * Method to change this.collapsed to false when the slide animation ends and is sliding open * @param event The animation event @@ -164,20 +167,20 @@ export class SearchFilterComponent implements OnInit { * @returns {Observable} Emits true whenever a given filter config should be shown */ private isActive(): Observable { - return this.selectedValues$.pipe( - switchMap((isActive) => { - if (isNotEmpty(isActive)) { + return combineLatest([ + this.appliedFilters$, + this.searchConfigService.searchOptions, + ]).pipe( + switchMap(([selectedValues, options]: [AppliedFilter[], SearchOptions]) => { + if (isNotEmpty(selectedValues)) { return observableOf(true); } else { - return this.searchConfigService.searchOptions.pipe( - switchMap((options) => { - return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe( - filter((RD) => !RD.isLoading), - map((valuesRD) => { - return valuesRD.payload?.totalElements > 0; - }),); - } - )); + return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe( + filter((RD: RemoteData) => !RD.isLoading), + map((valuesRD: RemoteData) => { + return valuesRD.payload?.totalElements > 0; + }), + ); } }), startWith(true)); diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts index c3f73aa8997..9062d1011f9 100644 --- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.spec.ts @@ -1,6 +1,6 @@ import { SearchHierarchyFilterComponent } from './search-hierarchy-filter.component'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { DebugElement, EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; +import { DebugElement, EventEmitter, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { VocabularyService } from '../../../../../core/submission/vocabularies/vocabulary.service'; import { of as observableOf, BehaviorSubject } from 'rxjs'; @@ -26,6 +26,7 @@ import { SearchConfigurationServiceStub } from '../../../../testing/search-confi import { VocabularyEntryDetail } from '../../../../../core/submission/vocabularies/models/vocabulary-entry-detail.model'; import { AppliedFilter } from '../../../models/applied-filter.model'; import { SearchFilterConfig } from '../../../models/search-filter-config.model'; +import { SearchServiceStub } from '../../../../testing/search-service.stub'; describe('SearchHierarchyFilterComponent', () => { @@ -38,10 +39,7 @@ describe('SearchHierarchyFilterComponent', () => { select: new EventEmitter(), }; - const searchService = { - getSearchLink: () => testSearchLink, - getFacetValuesFor: () => observableOf([]), - }; + let searchService: SearchServiceStub; const searchFilterService = { getPage: () => observableOf(0), }; @@ -56,6 +54,8 @@ describe('SearchHierarchyFilterComponent', () => { }; beforeEach(() => { + searchService = new SearchServiceStub(); + TestBed.configureTestingModule({ imports: [ CommonModule, @@ -77,7 +77,7 @@ describe('SearchHierarchyFilterComponent', () => { { provide: FILTER_CONFIG, useValue: Object.assign(new SearchFilterConfig(), { name: testSearchFilter }) }, { provide: REFRESH_FILTER, useValue: new BehaviorSubject(false) }, ], - schemas: [NO_ERRORS_SCHEMA], + schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); }); diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 9cc9e88660f..c127ab125b4 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -1,7 +1,7 @@ -import { BehaviorSubject, combineLatest as observableCombineLatest, of as observableOf , Subscription } from 'rxjs'; +import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; import { isPlatformBrowser } from '@angular/common'; -import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; +import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core'; import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; import { FilterType } from '../../../models/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; @@ -19,8 +19,6 @@ import { SEARCH_CONFIG_SERVICE } from '../../../../../my-dspace-page/my-dspace-p import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service'; import { RouteService } from '../../../../../core/services/route.service'; import { hasValue } from '../../../../empty.util'; -import { AppliedFilter } from '../../../models/applied-filter.model'; -import { FacetValues } from '../../../models/facet-values.model'; import { yearFromString } from 'src/app/shared/date.util'; /** @@ -49,7 +47,7 @@ export const RANGE_FILTER_MAX_SUFFIX = '.max'; * Component that represents a range facet for a specific filter configuration */ @renderFacetFor(FilterType.range) -export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit, OnDestroy { +export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit { /** * Fallback minimum for the range */ @@ -65,11 +63,6 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple */ range: [number | undefined, number | undefined]; - /** - * Subscription to unsubscribe from - */ - sub: Subscription; - /** * Whether the sider is being controlled by the keyboard. * Supresses any changes until the key is released. @@ -100,25 +93,13 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple this.max = yearFromString(this.filterConfig.maxValue) || this.max; const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX).pipe(startWith(undefined)); const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX).pipe(startWith(undefined)); - this.sub = observableCombineLatest([iniMin, iniMax]).pipe( + this.subs.push(observableCombineLatest([iniMin, iniMax]).pipe( map(([min, max]: [string, string]) => { const minimum = hasValue(min) ? Number(min) : this.min; const maximum = hasValue(max) ? Number(max) : this.max; return [minimum, maximum]; }) - ).subscribe((minmax: [number, number]) => this.range = minmax); - } - - setAppliedFilter(allFacetValues: FacetValues[]): void { - const appliedFilters: AppliedFilter[] = [].concat(...allFacetValues.map((facetValues: FacetValues) => facetValues.appliedFilters)) - .filter((appliedFilter: AppliedFilter) => hasValue(appliedFilter)) - .filter((appliedFilter: AppliedFilter) => appliedFilter.filter === this.filterConfig.name) - // TODO this should ideally be fixed in the backend - .map((appliedFilter: AppliedFilter) => Object.assign({}, appliedFilter, { - operator: 'range', - })); - - this.selectedAppliedFilters$ = observableOf(appliedFilters); + ).subscribe((minmax: [number, number]) => this.range = minmax)); } /** @@ -159,13 +140,4 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple return isPlatformBrowser(this.platformId); } - /** - * Unsubscribe from all subscriptions - */ - ngOnDestroy() { - super.ngOnDestroy(); - if (hasValue(this.sub)) { - this.sub.unsubscribe(); - } - } } diff --git a/src/app/shared/testing/search-filter-service.stub.ts b/src/app/shared/testing/search-filter-service.stub.ts index f732c98fb82..594c0dd525a 100644 --- a/src/app/shared/testing/search-filter-service.stub.ts +++ b/src/app/shared/testing/search-filter-service.stub.ts @@ -5,6 +5,9 @@ import { SearchFilterConfig } from '../search/models/search-filter-config.model' import { Params } from '@angular/router'; /* eslint-disable no-empty,@typescript-eslint/no-empty-function */ +/** + * Stub class of {@link SearchFilterService} + */ export class SearchFilterServiceStub { isFilterActiveWithValue(_paramName: string, _filterValue: string): Observable { @@ -39,10 +42,6 @@ export class SearchFilterServiceStub { return observableOf(undefined); } - getSelectedValuesForFilter(_filterConfig: SearchFilterConfig): Observable { - return observableOf([]); - } - isCollapsed(_filterName: string): Observable { return observableOf(true); } diff --git a/src/app/shared/testing/search-service.stub.ts b/src/app/shared/testing/search-service.stub.ts index 9a47c666c9e..f5bba3659d1 100644 --- a/src/app/shared/testing/search-service.stub.ts +++ b/src/app/shared/testing/search-service.stub.ts @@ -2,7 +2,11 @@ import {of as observableOf, Observable , BehaviorSubject } from 'rxjs'; import { ViewMode } from '../../core/shared/view-mode.model'; import { SearchFilterConfig } from '../search/models/search-filter-config.model'; import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model'; +import { AppliedFilter } from '../search/models/applied-filter.model'; +/** + * Stub class of {@link SearchService} + */ export class SearchServiceStub { private _viewMode: ViewMode; @@ -14,6 +18,10 @@ export class SearchServiceStub { this.setViewMode(ViewMode.ListElement); } + getSelectedValuesForFilter(_filterName: string): Observable { + return observableOf([]); + } + getViewMode(): Observable { return this.viewMode; }