mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 13:03:04 +00:00
second part of docs
This commit is contained in:
@@ -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 {
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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 + ')';
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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'],
|
||||||
|
@@ -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
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
}
|
}
|
||||||
|
@@ -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>
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user