diff --git a/src/app/+search-page/filtered-search-page.component.ts b/src/app/+search-page/filtered-search-page.component.ts index d577c2c44c..df37d3f441 100644 --- a/src/app/+search-page/filtered-search-page.component.ts +++ b/src/app/+search-page/filtered-search-page.component.ts @@ -54,5 +54,4 @@ export class FilteredSearchPageComponent extends SearchPageComponent { this.searchConfigService.updateFixedFilter(this.fixedFilterQuery); return this.searchConfigService.paginatedSearchOptions; } - } diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts index 39acd19ccd..75caf93d57 100644 --- a/src/app/+search-page/search-service/search-configuration.service.ts +++ b/src/app/+search-page/search-service/search-configuration.service.ts @@ -9,7 +9,7 @@ import { of as observableOf, Subscription } from 'rxjs'; -import { filter, flatMap, map } from 'rxjs/operators'; +import { filter, flatMap, map, tap } from 'rxjs/operators'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { SearchOptions } from '../search-options.model'; @@ -99,10 +99,8 @@ export class SearchConfigurationService implements OnDestroy { const defs = defRD.payload; this.paginatedSearchOptions = new BehaviorSubject(defs); this.searchOptions = new BehaviorSubject(defs); - this.subs.push(this.subscribeToSearchOptions(defs)); this.subs.push(this.subscribeToPaginatedSearchOptions(defs)); - } ) } @@ -357,7 +355,8 @@ export class SearchConfigurationService implements OnDestroy { isNotEmptyOperator(), map((fixedFilter) => { return { fixedFilter } - }) + }), + tap(t => console.log(t)) ); } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index da01b1297a..37cc791558 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -57,7 +57,6 @@ export class AppComponent implements OnInit, AfterViewInit { private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, private authService: AuthService, private router: Router, - private routeService: RouteService, private cssService: CSSVariableService, private menuService: MenuService, private windowService: HostWindowService @@ -77,13 +76,10 @@ export class AppComponent implements OnInit, AfterViewInit { metadata.listenForRouteChange(); - routeService.saveRouting(); - if (config.debug) { console.info(config); } this.storeCSSVariables(); - } ngOnInit() { diff --git a/src/app/core/core.reducers.ts b/src/app/core/core.reducers.ts index c93b4bf44b..7aecb91a7a 100644 --- a/src/app/core/core.reducers.ts +++ b/src/app/core/core.reducers.ts @@ -13,6 +13,7 @@ import { objectUpdatesReducer, ObjectUpdatesState } from './data/object-updates/object-updates.reducer'; +import { routeReducer, RouteState } from '../shared/services/route.reducer'; export interface CoreState { 'cache/object': ObjectCacheState, @@ -21,7 +22,8 @@ export interface CoreState { 'data/request': RequestState, 'index': MetaIndexState, 'auth': AuthState, - 'json/patch': JsonPatchOperationsState + 'json/patch': JsonPatchOperationsState, + 'route': RouteState } export const coreReducers: ActionReducerMap = { @@ -31,5 +33,6 @@ export const coreReducers: ActionReducerMap = { 'data/request': requestReducer, 'index': indexReducer, 'auth': authReducer, - 'json/patch': jsonPatchOperationsReducer + 'json/patch': jsonPatchOperationsReducer, + 'route': routeReducer }; diff --git a/src/app/core/index/index.actions.ts b/src/app/core/index/index.actions.ts index 98d07d59d5..42804dbe26 100644 --- a/src/app/core/index/index.actions.ts +++ b/src/app/core/index/index.actions.ts @@ -14,7 +14,7 @@ export const IndexActionTypes = { /* tslint:disable:max-classes-per-file */ /** - * An ngrx action to add an value to the index + * An ngrx action to add a value to the index */ export class AddToIndexAction implements Action { type = IndexActionTypes.ADD; @@ -40,7 +40,7 @@ export class AddToIndexAction implements Action { } /** - * An ngrx action to remove an value from the index + * An ngrx action to remove a value from the index */ export class RemoveFromIndexByValueAction implements Action { type = IndexActionTypes.REMOVE_BY_VALUE; diff --git a/src/app/shared/services/route.action.ts b/src/app/shared/services/route.action.ts new file mode 100644 index 0000000000..fe54db02e2 --- /dev/null +++ b/src/app/shared/services/route.action.ts @@ -0,0 +1,103 @@ +import { Action } from '@ngrx/store'; +import { type } from '../../shared/ngrx/type'; +import { Params } from '@angular/router'; + +/** + * The list of HrefIndexAction type definitions + */ +export const RouteActionTypes = { + SET_QUERY_PARAMETERS: type('dspace/core/route/SET_QUERY_PARAMETERS'), + SET_PARAMETERS: type('dspace/core/route/SET_PARAMETERS'), + ADD_QUERY_PARAMETER: type('dspace/core/route/ADD_QUERY_PARAMETER'), + ADD_PARAMETER: type('dspace/core/route/ADD_PARAMETER'), +}; + +/* tslint:disable:max-classes-per-file */ +/** + * An ngrx action to set the query parameters + */ +export class SetQueryParametersAction implements Action { + type = RouteActionTypes.SET_QUERY_PARAMETERS; + payload: Params; + + /** + * Create a new SetQueryParametersAction + * + * @param parameters + * the query parameters + */ + constructor(parameters: Params) { + this.payload = parameters; + } +} + +/** + * An ngrx action to set the parameters + */ +export class SetParametersAction implements Action { + type = RouteActionTypes.SET_PARAMETERS; + payload: Params; + + /** + * Create a new SetParametersAction + * + * @param parameters + * the parameters + */ + constructor(parameters: Params) { + this.payload = parameters; + } +} + +/** + * An ngrx action to add a query parameter + */ +export class AddQueryParameterAction implements Action { + type = RouteActionTypes.ADD_QUERY_PARAMETER; + payload: { + key: string; + value: string; + }; + + /** + * Create a new AddQueryParameterAction + * + * @param key + * the key to add + * @param value + * the value of this key + */ + constructor(key: string, value: string) { + this.payload = { key, value }; + } +} + +/** + * An ngrx action to add a parameter + */ +export class AddParameterAction implements Action { + type = RouteActionTypes.ADD_PARAMETER; + payload: { + key: string; + value: string; + }; + + /** + * Create a new AddParameterAction + * + * @param key + * the key to add + * @param value + * the value of this key + */ + constructor(key: string, value: string) { + this.payload = { key, value }; + } +} + +/* tslint:enable:max-classes-per-file */ + +/** + * A type to encompass all RouteActions + */ +export type RouteAction = SetQueryParametersAction | SetParametersAction | AddQueryParameterAction | AddParameterAction; diff --git a/src/app/shared/services/route.reducer.ts b/src/app/shared/services/route.reducer.ts new file mode 100644 index 0000000000..37fe06283b --- /dev/null +++ b/src/app/shared/services/route.reducer.ts @@ -0,0 +1,49 @@ +import { Params } from '@angular/router'; +import { + AddParameterAction, + AddQueryParameterAction, + RouteAction, + RouteActionTypes, SetParametersAction, SetQueryParametersAction +} from './route.action'; + +export interface RouteState { + queryParams: Params; + params: Params; +} + +const initialState: RouteState = { + queryParams: {}, + params: {} +}; + +export function routeReducer(state = initialState, action: RouteAction): RouteState { + switch (action.type) { + case RouteActionTypes.SET_PARAMETERS: { + return setParameters(state, action as SetParametersAction, 'params'); + } + case RouteActionTypes.SET_QUERY_PARAMETERS: { + return setParameters(state, action as SetQueryParametersAction, 'queryParams'); + } + case RouteActionTypes.ADD_PARAMETER: { + return addParameter(state, action as AddParameterAction, 'params'); + } + case RouteActionTypes.ADD_QUERY_PARAMETER: { + return addParameter(state, action as AddQueryParameterAction, 'queryParams'); + } + default: { + return state; + } + } +} + +function addParameter(state: RouteState, action: AddParameterAction | AddQueryParameterAction, paramType: string): RouteState { + const subState = state[paramType]; + const existingValues = subState[action.payload.key] || []; + const newValues = [...existingValues, action.payload.value]; + const newSubstate = Object.assign(subState, { [action.payload.key]: newValues }); + return Object.assign({}, state, { [paramType]: newSubstate }); +} + +function setParameters(state: RouteState, action: SetParametersAction | SetQueryParametersAction, paramType: string): RouteState { + return Object.assign({}, state, { [paramType]: action.payload }); +} diff --git a/src/app/shared/services/route.service.ts b/src/app/shared/services/route.service.ts index a94b7e56da..d6f8dabee9 100644 --- a/src/app/shared/services/route.service.ts +++ b/src/app/shared/services/route.service.ts @@ -1,4 +1,4 @@ -import { distinctUntilChanged, filter, map, mergeMap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { ActivatedRoute, @@ -8,24 +8,46 @@ import { RouterStateSnapshot, } from '@angular/router'; -import { Observable } from 'rxjs'; -import { select, Store } from '@ngrx/store'; +import { combineLatest, Observable } from 'rxjs'; +import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { isEqual } from 'lodash'; -import { AppState } from '../../app.reducer'; import { AddUrlToHistoryAction } from '../history/history.actions'; import { historySelector } from '../history/selectors'; +import { SetParametersAction, SetQueryParametersAction } from './route.action'; +import { CoreState } from '../../core/core.reducers'; +import { hasValue } from '../empty.util'; +import { coreSelector } from '../../core/core.selectors'; + +export const routeParametersSelector = createSelector( + coreSelector, + (state: CoreState) => state['route'].params +); +export const queryParametersSelector = createSelector( + coreSelector, + (state: CoreState) => state['route'].queryParams +); + +export const routeParameterSelector = (key: string) => parameterSelector(key, routeParametersSelector); +export const queryParameterSelector = (key: string) => parameterSelector(key, queryParametersSelector); + +export function parameterSelector(key: string, paramsSelector: (state: CoreState) => Params): MemoizedSelector { + return createSelector(paramsSelector, (state: Params) => { + if (hasValue(state)) { + return state[key]; + } else { + return undefined; + } + }); +} /** * Service to keep track of the current query parameters */ @Injectable() export class RouteService { - params: Observable; - - constructor(private route: ActivatedRoute, private router: Router, private store: Store) { - this.subscribeToRouterParams(); - + constructor(private route: ActivatedRoute, private router: Router, private store: Store) { + this.saveRouting(); } /** @@ -74,11 +96,11 @@ export class RouteService { } getRouteParameterValue(paramName: string): Observable { - return this.params.pipe(map((params) => params[paramName]),distinctUntilChanged(),); + return this.store.pipe(select(routeParameterSelector(paramName)), tap((t) => console.log(paramName, t))); } getRouteDataValue(datafield: string): Observable { - return this.route.data.pipe(map((data) => data[datafield]),distinctUntilChanged(),); + return this.route.data.pipe(map((data) => data[datafield]), distinctUntilChanged(),); } /** @@ -114,23 +136,23 @@ export class RouteService { } public saveRouting(): void { - this.router.events - .pipe(filter((event) => event instanceof NavigationEnd)) - .subscribe(({ urlAfterRedirects }: NavigationEnd) => { - this.store.dispatch(new AddUrlToHistoryAction(urlAfterRedirects)) + combineLatest(this.router.events, this.getRouteParams(), this.route.queryParams) + .pipe(filter(([event, params, queryParams]) => event instanceof NavigationEnd)) + .subscribe(([event, params, queryParams]: [NavigationEnd, Params, Params]) => { + console.log(params); + this.store.dispatch(new SetParametersAction(params)); + this.store.dispatch(new SetQueryParametersAction(queryParams)); + this.store.dispatch(new AddUrlToHistoryAction(event.urlAfterRedirects)); }); } - subscribeToRouterParams() { - this.params = this.router.events.pipe( - mergeMap((event) => { - let active = this.route; - while (active.firstChild) { - active = active.firstChild; - } - return active.params; - }) - ); + private getRouteParams(): Observable { + let active = this.route; + console.log(active); + while (active.firstChild) { + active = active.firstChild; + } + return active.params; } public getHistory(): Observable {