second part of docs

This commit is contained in:
lotte
2018-07-26 14:25:30 +02:00
parent e7cc6a07f2
commit 38d1f6c85a
11 changed files with 259 additions and 55 deletions

View File

@@ -1,5 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { FilterType } from '../../../search-service/filter-type.model'; import { FilterType } from '../../../search-service/filter-type.model';
import { renderFacetFor } from '../search-filter-type-decorator'; import { renderFacetFor } from '../search-filter-type-decorator';
import { import {
@@ -7,11 +6,6 @@ import {
SearchFacetFilterComponent SearchFacetFilterComponent
} from '../search-facet-filter/search-facet-filter.component'; } from '../search-facet-filter/search-facet-filter.component';
/**
* This component renders a simple item page.
* The route parameter 'id' is used to request the item it represents.
* All fields of the item that should be displayed, are defined in its template.
*/
@Component({ @Component({
selector: 'ds-search-boolean-filter', selector: 'ds-search-boolean-filter',
@@ -20,6 +14,9 @@ import {
animations: [facetLoad] animations: [facetLoad]
}) })
/**
* Component that represents a boolean facet for a specific filter configuration
*/
@renderFacetFor(FilterType.boolean) @renderFacetFor(FilterType.boolean)
export class SearchBooleanFilterComponent extends SearchFacetFilterComponent implements OnInit { export class SearchBooleanFilterComponent extends SearchFacetFilterComponent implements OnInit {
} }

View File

@@ -3,20 +3,32 @@ import { renderFilterType } from '../search-filter-type-decorator';
import { FilterType } from '../../../search-service/filter-type.model'; import { FilterType } from '../../../search-service/filter-type.model';
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
import { FILTER_CONFIG } from '../search-filter.service'; import { FILTER_CONFIG } from '../search-filter.service';
import { Observable } from 'rxjs/Observable';
@Component({ @Component({
selector: 'ds-search-facet-filter-wrapper', selector: 'ds-search-facet-filter-wrapper',
templateUrl: './search-facet-filter-wrapper.component.html' templateUrl: './search-facet-filter-wrapper.component.html'
}) })
/**
* Wrapper component that renders a specific facet filter based on the filter config's type
*/
export class SearchFacetFilterWrapperComponent implements OnInit { export class SearchFacetFilterWrapperComponent implements OnInit {
/**
* Configuration for the filter of this wrapper component
*/
@Input() filterConfig: SearchFilterConfig; @Input() filterConfig: SearchFilterConfig;
@Input() selectedValues: Observable<string[]>;
/**
* Injector to inject a child component with the @Input parameters
*/
objectInjector: Injector; objectInjector: Injector;
constructor(private injector: Injector) { constructor(private injector: Injector) {
} }
/**
* Initialize and add the filter config to the injector
*/
ngOnInit(): void { ngOnInit(): void {
this.objectInjector = Injector.create({ this.objectInjector = Injector.create({
providers: [ providers: [
@@ -26,7 +38,10 @@ export class SearchFacetFilterWrapperComponent implements OnInit {
}); });
} }
getSearchFilter(): string { /**
* Find the correct component based on the filter config's type
*/
getSearchFilter() {
const type: FilterType = this.filterConfig.type; const type: FilterType = this.filterConfig.type;
return renderFilterType(type); return renderFilterType(type);
} }

View File

@@ -16,27 +16,54 @@ import { SearchFilterConfig } from '../../../search-service/search-filter-config
import { SearchService } from '../../../search-service/search.service'; import { SearchService } from '../../../search-service/search.service';
import { FILTER_CONFIG, SearchFilterService } from '../search-filter.service'; import { FILTER_CONFIG, SearchFilterService } from '../search-filter.service';
/**
* This component renders a simple item page.
* The route parameter 'id' is used to request the item it represents.
* All fields of the item that should be displayed, are defined in its template.
*/
@Component({ @Component({
selector: 'ds-search-facet-filter', selector: 'ds-search-facet-filter',
template: ``, template: ``,
}) })
/**
* Super class for all different representations of facets
*/
export class SearchFacetFilterComponent implements OnInit, OnDestroy { export class SearchFacetFilterComponent implements OnInit, OnDestroy {
filterValues: Array<Observable<RemoteData<PaginatedList<FacetValue>>>> = []; /**
* Emits an array of pages with values found for this facet
*/
filterValues$: Subject<RemoteData<Array<PaginatedList<FacetValue>>>>; filterValues$: Subject<RemoteData<Array<PaginatedList<FacetValue>>>>;
/**
* Emits the current last shown page of this facet's values
*/
currentPage: Observable<number>; currentPage: Observable<number>;
/**
* Emits true if the current page is also the last page available
*/
isLastPage$: BehaviorSubject<boolean> = new BehaviorSubject(false); isLastPage$: BehaviorSubject<boolean> = new BehaviorSubject(false);
/**
* The value of the input field that is used to query for possible values for this filter
*/
filter: string; filter: string;
/**
* List of subscriptions to unsubscribe from
*/
private subs: Subscription[] = []; private subs: Subscription[] = [];
/**
* Emits the result values for this filter found by the current filter query
*/
filterSearchResults: Observable<any[]> = Observable.of([]); filterSearchResults: Observable<any[]> = Observable.of([]);
/**
* Emits the active values for this filter
*/
selectedValues: Observable<string[]>; selectedValues: Observable<string[]>;
private collapseNextUpdate = true; private collapseNextUpdate = true;
/**
* State of the requested facets used to time the animation
*/
animationState = 'loading'; animationState = 'loading';
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
@@ -46,12 +73,15 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
@Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig) { @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig) {
} }
/**
* Initializes all observable instance variables and starts listening to them
*/
ngOnInit(): void { ngOnInit(): void {
this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined)); this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined));
this.currentPage = this.getCurrentPage().distinctUntilChanged(); this.currentPage = this.getCurrentPage().distinctUntilChanged();
this.selectedValues = this.filterService.getSelectedValuesForFilter(this.filterConfig); this.selectedValues = this.filterService.getSelectedValuesForFilter(this.filterConfig);
const searchOptions = this.filterService.getSearchOptions().distinctUntilChanged(); const searchOptions = this.filterService.getSearchOptions().distinctUntilChanged();
this.subs.push(searchOptions.subscribe((options) => this.updateFilterValueList(options))); this.subs.push(searchOptions.subscribe((options) => this.updateFilterValueList()));
const facetValues = Observable.combineLatest(searchOptions, this.currentPage, (options, page) => { const facetValues = Observable.combineLatest(searchOptions, this.currentPage, (options, page) => {
return { return {
@@ -59,7 +89,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
page: page page: page
}; };
}); });
let filterValues = [];
this.subs.push(facetValues.subscribe((facetOutcome) => { this.subs.push(facetValues.subscribe((facetOutcome) => {
const newValues$ = facetOutcome.values; const newValues$ = facetOutcome.values;
@@ -69,12 +99,12 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
this.collapseNextUpdate = false; this.collapseNextUpdate = false;
} }
if (facetOutcome.page === 1) { if (facetOutcome.page === 1) {
this.filterValues = []; filterValues = [];
} }
this.filterValues = [...this.filterValues, newValues$]; filterValues = [...filterValues, newValues$];
this.subs.push(this.rdbs.aggregate(this.filterValues).subscribe((rd: RemoteData<Array<PaginatedList<FacetValue>>>) => { this.subs.push(this.rdbs.aggregate(filterValues).subscribe((rd: RemoteData<Array<PaginatedList<FacetValue>>>) => {
this.animationState = 'ready'; this.animationState = 'ready';
this.filterValues$.next(rd); this.filterValues$.next(rd);
})); }));
@@ -85,37 +115,61 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
} }
updateFilterValueList(options: SearchOptions) { /**
* Prepare for refreshing the values of this filter
*/
updateFilterValueList() {
this.animationState = 'loading'; this.animationState = 'loading';
this.collapseNextUpdate = true; this.collapseNextUpdate = true;
this.filter = ''; this.filter = '';
} }
/**
* Checks if a value for this filter is currently active
*/
isChecked(value: FacetValue): Observable<boolean> { isChecked(value: FacetValue): Observable<boolean> {
return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, value.value); return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, value.value);
} }
/**
* @returns {string} The base path to the search page
*/
getSearchLink() { getSearchLink() {
return this.searchService.getSearchLink(); return this.searchService.getSearchLink();
} }
/**
* Show the next page as well
*/
showMore() { showMore() {
this.filterService.incrementPage(this.filterConfig.name); this.filterService.incrementPage(this.filterConfig.name);
} }
/**
* Make sure only the first page is shown
*/
showFirstPageOnly() { showFirstPageOnly() {
// this.filterValues = [];
this.filterService.resetPage(this.filterConfig.name); this.filterService.resetPage(this.filterConfig.name);
} }
/**
* @returns {Observable<number>} The current page of this filter
*/
getCurrentPage(): Observable<number> { getCurrentPage(): Observable<number> {
return this.filterService.getPage(this.filterConfig.name); return this.filterService.getPage(this.filterConfig.name);
} }
/**
* @returns {string} the current URL
*/
getCurrentUrl() { getCurrentUrl() {
return this.router.url; return this.router.url;
} }
/**
* Submits a new active custom value to the filter from the input field
* @param data The string from the input field
*/
onSubmit(data: any) { onSubmit(data: any) {
this.selectedValues.first().subscribe((selectedValues) => { this.selectedValues.first().subscribe((selectedValues) => {
if (isNotEmpty(data)) { if (isNotEmpty(data)) {
@@ -139,6 +193,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
return hasValue(o); return hasValue(o);
} }
/**
* Calculates the parameters that should change if a given value for this filter would be removed from the active filters
* @param {string} value The value that is removed for this filter
* @returns {Observable<any>} The changed filter parameters
*/
getRemoveParams(value: string): Observable<any> { getRemoveParams(value: string): Observable<any> {
return this.selectedValues.map((selectedValues) => { return this.selectedValues.map((selectedValues) => {
return { return {
@@ -148,6 +207,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
}); });
} }
/**
* Calculates the parameters that should change if a given value for this filter would be added to the active filters
* @param {string} value The value that is added for this filter
* @returns {Observable<any>} The changed filter parameters
*/
getAddParams(value: string): Observable<any> { getAddParams(value: string): Observable<any> {
return this.selectedValues.map((selectedValues) => { return this.selectedValues.map((selectedValues) => {
return { return {
@@ -157,12 +221,20 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
}); });
} }
/**
* Unsubscribe from all subscriptions
*/
ngOnDestroy(): void { ngOnDestroy(): void {
this.subs this.subs
.filter((sub) => hasValue(sub)) .filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe()); .forEach((sub) => sub.unsubscribe());
} }
/**
* Updates the found facet value suggestions for a given query
* Transforms the found values into display values
* @param data The query for which is being searched
*/
findSuggestions(data): void { findSuggestions(data): void {
if (isNotEmpty(data)) { if (isNotEmpty(data)) {
this.filterService.getSearchOptions().first().subscribe( this.filterService.getSearchOptions().first().subscribe(
@@ -183,6 +255,12 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
} }
} }
/**
* Transforms the facet value string, so if the query matches part of the value, it's emphasized in the value
* @param {FacetValue} facet The value of the facet as returned by the server
* @param {string} query The query that was used to search facet values
* @returns {string} The facet value with the query part emphasized
*/
getDisplayValue(facet: FacetValue, query: string): string { getDisplayValue(facet: FacetValue, query: string): string {
return new EmphasizePipe().transform(facet.value, query) + ' (' + facet.count + ')'; return new EmphasizePipe().transform(facet.value, query) + ' (' + facet.count + ')';
} }

View File

@@ -3,6 +3,11 @@ import { FilterType } from '../../search-service/filter-type.model';
const filterTypeMap = new Map(); const filterTypeMap = new Map();
/**
* Sets the mapping for a component in relation to a filter type
* @param {FilterType} type The type for which the matching component is mapped
* @returns Decorator function that performs the actual mapping on initialization of the component
*/
export function renderFacetFor(type: FilterType) { export function renderFacetFor(type: FilterType) {
return function decorator(objectElement: any) { return function decorator(objectElement: any) {
if (!objectElement) { if (!objectElement) {
@@ -12,6 +17,11 @@ export function renderFacetFor(type: FilterType) {
}; };
} }
/**
* Requests the matching component based on a given filter type
* @param {FilterType} type The filter type for which the component is requested
* @returns The component's constructor that matches the given filter type
*/
export function renderFilterType(type: FilterType) { export function renderFilterType(type: FilterType) {
return filterTypeMap.get(type); return filterTypeMap.get(type);
} }

View File

@@ -5,12 +5,6 @@ import { Observable } from 'rxjs/Observable';
import { slide } from '../../../shared/animations/slide'; import { slide } from '../../../shared/animations/slide';
import { isNotEmpty } from '../../../shared/empty.util'; import { isNotEmpty } from '../../../shared/empty.util';
/**
* This component renders a simple item page.
* The route parameter 'id' is used to request the item it represents.
* All fields of the item that should be displayed, are defined in its template.
*/
@Component({ @Component({
selector: 'ds-search-filter', selector: 'ds-search-filter',
styleUrls: ['./search-filter.component.scss'], styleUrls: ['./search-filter.component.scss'],

View File

@@ -1,16 +1,16 @@
import { SearchFilterAction, SearchFilterActionTypes } from './search-filter.actions'; import { SearchFilterAction, SearchFilterActionTypes } from './search-filter.actions';
import { isEmpty } from '../../../shared/empty.util'; import { isEmpty } from '../../../shared/empty.util';
/* /**
Interface that represents the state for a single filters * Interface that represents the state for a single filters
*/ */
export interface SearchFilterState { export interface SearchFilterState {
filterCollapsed: boolean, filterCollapsed: boolean,
page: number page: number
} }
/* /**
Interface that represents the state for all available filters * Interface that represents the state for all available filters
*/ */
export interface SearchFiltersState { export interface SearchFiltersState {
[name: string]: SearchFilterState [name: string]: SearchFilterState

View File

@@ -34,22 +34,42 @@ export class SearchFilterService {
private route: ActivatedRoute) { private route: ActivatedRoute) {
} }
/**
* Checks if a given filter is active with a given value
* @param {string} paramName The parameter name of the filter's configuration for which to search
* @param {string} filterValue The value for which to search
* @returns {Observable<boolean>} Emit true when the filter is active with the given value
*/
isFilterActiveWithValue(paramName: string, filterValue: string): Observable<boolean> { isFilterActiveWithValue(paramName: string, filterValue: string): Observable<boolean> {
return this.routeService.hasQueryParamWithValue(paramName, filterValue); return this.routeService.hasQueryParamWithValue(paramName, filterValue);
} }
/**
* Checks if a given filter is active with any value
* @param {string} paramName The parameter name of the filter's configuration for which to search
* @returns {Observable<boolean>} Emit true when the filter is active with any value
*/
isFilterActive(paramName: string): Observable<boolean> { isFilterActive(paramName: string): Observable<boolean> {
return this.routeService.hasQueryParam(paramName); return this.routeService.hasQueryParam(paramName);
} }
/**
* @returns {Observable<string>} Emits the current scope's identifier
*/
getCurrentScope() { getCurrentScope() {
return this.routeService.getQueryParameterValue('scope'); return this.routeService.getQueryParameterValue('scope');
} }
/**
* @returns {Observable<string>} Emits the current query string
*/
getCurrentQuery() { getCurrentQuery() {
return this.routeService.getQueryParameterValue('query'); return this.routeService.getQueryParameterValue('query');
} }
/**
* @returns {Observable<string>} Emits the current pagination settings
*/
getCurrentPagination(pagination: any = {}): Observable<PaginationComponentOptions> { getCurrentPagination(pagination: any = {}): Observable<PaginationComponentOptions> {
const page$ = this.routeService.getQueryParameterValue('page'); const page$ = this.routeService.getQueryParameterValue('page');
const size$ = this.routeService.getQueryParameterValue('pageSize'); const size$ = this.routeService.getQueryParameterValue('pageSize');
@@ -61,6 +81,9 @@ export class SearchFilterService {
}); });
} }
/**
* @returns {Observable<string>} Emits the current sorting settings
*/
getCurrentSort(defaultSort: SortOptions): Observable<SortOptions> { getCurrentSort(defaultSort: SortOptions): Observable<SortOptions> {
const sortDirection$ = this.routeService.getQueryParameterValue('sortDirection'); const sortDirection$ = this.routeService.getQueryParameterValue('sortDirection');
const sortField$ = this.routeService.getQueryParameterValue('sortField'); const sortField$ = this.routeService.getQueryParameterValue('sortField');
@@ -75,6 +98,9 @@ export class SearchFilterService {
); );
} }
/**
* @returns {Observable<Params>} Emits the current active filters with their values as they are sent to the backend
*/
getCurrentFilters(): Observable<Params> { getCurrentFilters(): Observable<Params> {
return this.routeService.getQueryParamsWithPrefix('f.').map((filterParams) => { return this.routeService.getQueryParamsWithPrefix('f.').map((filterParams) => {
if (isNotEmpty(filterParams)) { if (isNotEmpty(filterParams)) {
@@ -97,14 +123,24 @@ export class SearchFilterService {
}); });
} }
/**
* @returns {Observable<Params>} Emits the current active filters with their values as they are displayed in the frontend URL
*/
getCurrentFrontendFilters(): Observable<Params> { getCurrentFrontendFilters(): Observable<Params> {
return this.routeService.getQueryParamsWithPrefix('f.'); return this.routeService.getQueryParamsWithPrefix('f.');
} }
/**
* @returns {Observable<string>} Emits the current UI list view
*/
getCurrentView() { getCurrentView() {
return this.routeService.getQueryParameterValue('view'); return this.routeService.getQueryParameterValue('view');
} }
/**
* @param defaults The default values for the search options, that will be used if nothing is explicitly set
* @returns {Observable<PaginatedSearchOptions>} Emits the current paginated search options
*/
getPaginatedSearchOptions(defaults: any = {}): Observable<PaginatedSearchOptions> { getPaginatedSearchOptions(defaults: any = {}): Observable<PaginatedSearchOptions> {
return Observable.combineLatest( return Observable.combineLatest(
this.getCurrentPagination(defaults.pagination), this.getCurrentPagination(defaults.pagination),
@@ -129,6 +165,10 @@ export class SearchFilterService {
) )
} }
/**
* @param defaults The default values for the search options, that will be used if nothing is explicitly set
* @returns {Observable<PaginatedSearchOptions>} Emits the current search options
*/
getSearchOptions(defaults: any = {}): Observable<SearchOptions> { getSearchOptions(defaults: any = {}): Observable<SearchOptions> {
return Observable.combineLatest( return Observable.combineLatest(
this.getCurrentView(), this.getCurrentView(),
@@ -148,9 +188,14 @@ export class SearchFilterService {
) )
} }
/**
* Requests the active filter values set for a given filter
* @param {SearchFilterConfig} filterConfig The configuration for which the filters are active
* @returns {Observable<string[]>} Emits the active filters for the given filter configuration
*/
getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> { getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> {
const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName); const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName);
const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').map((params: Params) => [].concat(...Object.values(params))); const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').map((params: Params) => [].concat(...Object.values(params)));
return Observable.combineLatest(values$, prefixValues$, (values, prefixValues) => { return Observable.combineLatest(values$, prefixValues$, (values, prefixValues) => {
if (isNotEmpty(values)) { if (isNotEmpty(values)) {
return values; return values;
@@ -159,6 +204,11 @@ export class SearchFilterService {
}) })
} }
/**
* Checks if the state of a given filter is currently collapsed or not
* @param {string} filterName The filtername for which the collapsed state is checked
* @returns {Observable<boolean>} Emits the current collapsed state of the given filter, if it's unavailable, return false
*/
isCollapsed(filterName: string): Observable<boolean> { isCollapsed(filterName: string): Observable<boolean> {
return this.store.select(filterByNameSelector(filterName)) return this.store.select(filterByNameSelector(filterName))
.map((object: SearchFilterState) => { .map((object: SearchFilterState) => {
@@ -170,6 +220,11 @@ export class SearchFilterService {
}); });
} }
/**
* Request the current page of a given filter
* @param {string} filterName The filtername for which the page state is checked
* @returns {Observable<boolean>} Emits the current page state of the given filter, if it's unavailable, return 1
*/
getPage(filterName: string): Observable<number> { getPage(filterName: string): Observable<number> {
return this.store.select(filterByNameSelector(filterName)) return this.store.select(filterByNameSelector(filterName))
.map((object: SearchFilterState) => { .map((object: SearchFilterState) => {
@@ -181,34 +236,65 @@ export class SearchFilterService {
}); });
} }
/**
* Dispatches a collapse action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public collapse(filterName: string): void { public collapse(filterName: string): void {
this.store.dispatch(new SearchFilterCollapseAction(filterName)); this.store.dispatch(new SearchFilterCollapseAction(filterName));
} }
/**
* Dispatches a expand action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public expand(filterName: string): void { public expand(filterName: string): void {
this.store.dispatch(new SearchFilterExpandAction(filterName)); this.store.dispatch(new SearchFilterExpandAction(filterName));
} }
/**
* Dispatches a toggle action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public toggle(filterName: string): void { public toggle(filterName: string): void {
this.store.dispatch(new SearchFilterToggleAction(filterName)); this.store.dispatch(new SearchFilterToggleAction(filterName));
} }
/**
* Dispatches a initial collapse action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public initialCollapse(filterName: string): void { public initialCollapse(filterName: string): void {
this.store.dispatch(new SearchFilterInitialCollapseAction(filterName)); this.store.dispatch(new SearchFilterInitialCollapseAction(filterName));
} }
/**
* Dispatches a initial expand action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public initialExpand(filterName: string): void { public initialExpand(filterName: string): void {
this.store.dispatch(new SearchFilterInitialExpandAction(filterName)); this.store.dispatch(new SearchFilterInitialExpandAction(filterName));
} }
/**
* Dispatches a decrement action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public decrementPage(filterName: string): void { public decrementPage(filterName: string): void {
this.store.dispatch(new SearchFilterDecrementPageAction(filterName)); this.store.dispatch(new SearchFilterDecrementPageAction(filterName));
} }
/**
* Dispatches a increment page action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public incrementPage(filterName: string): void { public incrementPage(filterName: string): void {
this.store.dispatch(new SearchFilterIncrementPageAction(filterName)); this.store.dispatch(new SearchFilterIncrementPageAction(filterName));
} }
/**
* Dispatches a reset page action to the store for a given filter
* @param {string} filterName The filter for which the action is dispatched
*/
public resetPage(filterName: string): void { public resetPage(filterName: string): void {
this.store.dispatch(new SearchFilterResetPageAction(filterName)); this.store.dispatch(new SearchFilterResetPageAction(filterName));
} }

View File

@@ -1,6 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FacetValue } from '../../../search-service/facet-value.model';
import { Observable } from 'rxjs/Observable';
import { FilterType } from '../../../search-service/filter-type.model'; import { FilterType } from '../../../search-service/filter-type.model';
import { renderFacetFor } from '../search-filter-type-decorator'; import { renderFacetFor } from '../search-filter-type-decorator';
import { import {
@@ -8,12 +6,6 @@ import {
SearchFacetFilterComponent SearchFacetFilterComponent
} from '../search-facet-filter/search-facet-filter.component'; } from '../search-facet-filter/search-facet-filter.component';
/**
* This component renders a simple item page.
* The route parameter 'id' is used to request the item it represents.
* All fields of the item that should be displayed, are defined in its template.
*/
@Component({ @Component({
selector: 'ds-search-hierarchy-filter', selector: 'ds-search-hierarchy-filter',
styleUrls: ['./search-hierarchy-filter.component.scss'], styleUrls: ['./search-hierarchy-filter.component.scss'],
@@ -21,6 +13,9 @@ import {
animations: [facetLoad] animations: [facetLoad]
}) })
/**
* Component that represents a hierarchy facet for a specific filter configuration
*/
@renderFacetFor(FilterType.hierarchy) @renderFacetFor(FilterType.hierarchy)
export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent implements OnInit { export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent implements OnInit {
} }

View File

@@ -28,7 +28,7 @@
<ng-container *ngFor="let value of page.page; let i=index"> <ng-container *ngFor="let value of page.page; let i=index">
<a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row" <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge"> [queryParams]="getChangeParams(value.value) | async" queryParamsHandling="merge">
<span class="filter-value px-1">{{value.value}}</span> <span class="filter-value px-1">{{value.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">
<span class="badge badge-secondary badge-pill">{{value.count}}</span> <span class="badge badge-secondary badge-pill">{{value.count}}</span>

View File

@@ -34,11 +34,29 @@ const rangeDelimiter = '-';
animations: [facetLoad] animations: [facetLoad]
}) })
/**
* Component that represents a range facet for a specific filter configuration
*/
@renderFacetFor(FilterType.range) @renderFacetFor(FilterType.range)
export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit, OnDestroy { export class SearchRangeFilterComponent extends SearchFacetFilterComponent implements OnInit, OnDestroy {
/**
* Fallback minimum for the range
*/
min = 1950; min = 1950;
/**
* Fallback maximum for the range
*/
max = 2018; max = 2018;
/**
* The current range of the filter
*/
range; range;
/**
* Subscription to unsubscribe from
*/
sub: Subscription; sub: Subscription;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
@@ -52,6 +70,10 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
} }
/**
* Initialize with the min and max values as configured in the filter configuration
* Set the initial values of the range
*/
ngOnInit(): void { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.min = moment(this.filterConfig.minValue, dateFormats).year() || this.min; this.min = moment(this.filterConfig.minValue, dateFormats).year() || this.min;
@@ -65,7 +87,12 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
}).subscribe((minmax) => this.range = minmax); }).subscribe((minmax) => this.range = minmax);
} }
getAddParams(value: string) { /**
* Calculates the parameters that should change if a given values for this range filter would be changed
* @param {string} value The values that are changed for this filter
* @returns {Observable<any>} The changed filter parameters
*/
getChangeParams(value: string) {
const parts = value.split(rangeDelimiter); const parts = value.split(rangeDelimiter);
const min = parts.length > 1 ? parts[0].trim() : value; const min = parts.length > 1 ? parts[0].trim() : value;
const max = parts.length > 1 ? parts[1].trim() : value; const max = parts.length > 1 ? parts[1].trim() : value;
@@ -77,16 +104,9 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
}); });
} }
getRemoveParams(value: string) { /**
return Observable.of( * Submits new custom range values to the range filter from the widget
{ */
[this.filterConfig.paramName + minSuffix]: null,
[this.filterConfig.paramName + maxSuffix]: null,
page: 1
}
);
}
onSubmit() { onSubmit() {
const newMin = this.range[0] !== this.min ? [this.range[0]] : null; const newMin = this.range[0] !== this.min ? [this.range[0]] : null;
const newMax = this.range[1] !== this.max ? [this.range[1]] : null; const newMax = this.range[1] !== this.max ? [this.range[1]] : null;
@@ -103,12 +123,18 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
/** /**
* TODO when upgrading nouislider, verify that this check is still needed. * TODO when upgrading nouislider, verify that this check is still needed.
* Prevents AoT bug
* @returns {boolean} True if the platformId is a platform browser
*/ */
shouldShowSlider(): boolean { shouldShowSlider(): boolean {
return isPlatformBrowser(this.platformId); return isPlatformBrowser(this.platformId);
} }
/**
* Unsubscribe from all subscriptions
*/
ngOnDestroy() { ngOnDestroy() {
super.ngOnDestroy();
if (hasValue(this.sub)) { if (hasValue(this.sub)) {
this.sub.unsubscribe(); this.sub.unsubscribe();
} }

View File

@@ -21,6 +21,9 @@ import { renderFacetFor } from '../search-filter-type-decorator';
animations: [facetLoad] animations: [facetLoad]
}) })
/**
* Component that represents a text facet for a specific filter configuration
*/
@renderFacetFor(FilterType.text) @renderFacetFor(FilterType.text)
export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit { export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit {
} }