diff --git a/modules/router-store/spec/integration.spec.ts b/modules/router-store/spec/integration.spec.ts index f164bf87a1..a75e7cae04 100644 --- a/modules/router-store/spec/integration.spec.ts +++ b/modules/router-store/spec/integration.spec.ts @@ -1,3 +1,4 @@ +import { StoreRouterConfig } from '../src/router_store_module'; import { Component, Provider } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { NavigationEnd, Router, RouterStateSnapshot } from '@angular/router'; @@ -411,6 +412,51 @@ describe('integration spec', () => { done(); }); }); + + it('should work when defining state key', (done: any) => { + const reducer = (state: string = '', action: RouterAction) => { + if (action.type === ROUTER_NAVIGATION) { + return action.payload.routerState.url.toString(); + } else { + return state; + } + }; + + createTestModule({ + reducers: { reducer }, + config: { stateKey: 'router-reducer' }, + }); + + const router: Router = TestBed.get(Router); + const store = TestBed.get(Store); + const log = logOfRouterAndStore(router, store); + + router + .navigateByUrl('/') + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '' }, // init event. has nothing to do with the router + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + }) + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); + }); }); function createTestModule( @@ -419,6 +465,7 @@ function createTestModule( canActivate?: Function; canLoad?: Function; providers?: Provider[]; + config?: StoreRouterConfig; } = {} ) { @Component({ @@ -450,7 +497,7 @@ function createTestModule( canLoad: ['CanLoadNext'], }, ]), - StoreRouterConnectingModule, + StoreRouterConnectingModule.forRoot(opts.config), ], providers: [ { diff --git a/modules/router-store/src/router_store_module.ts b/modules/router-store/src/router_store_module.ts index b65a5990b3..00d4f8a7de 100644 --- a/modules/router-store/src/router_store_module.ts +++ b/modules/router-store/src/router_store_module.ts @@ -1,4 +1,9 @@ -import { NgModule } from '@angular/core'; +import { + NgModule, + ModuleWithProviders, + InjectionToken, + Inject, +} from '@angular/core'; import { NavigationCancel, NavigationError, @@ -107,6 +112,11 @@ export function routerReducer( } } +export interface StoreRouterConfig { + stateKey?: string; +} +export const _ROUTER_CONFIG = new InjectionToken('@ngrx/router Configuration'); + /** * Connects RouterModule with StoreModule. * @@ -155,6 +165,14 @@ export function routerReducer( ], }) export class StoreRouterConnectingModule { + static forRoot(config?: StoreRouterConfig): ModuleWithProviders; + static forRoot(config: StoreRouterConfig = {}): ModuleWithProviders { + return { + ngModule: StoreRouterConnectingModule, + providers: [{ provide: _ROUTER_CONFIG, useValue: config }], + }; + } + private routerState: RouterStateSnapshot; private storeState: any; private lastRoutesRecognized: RoutesRecognized; @@ -162,11 +180,16 @@ export class StoreRouterConnectingModule { private dispatchTriggeredByRouter: boolean = false; // used only in dev mode in combination with routerReducer private navigationTriggeredByDispatch: boolean = false; // used only in dev mode in combination with routerReducer + private stateKey: string = 'routerReducer'; + constructor( private store: Store, private router: Router, - private serializer: RouterStateSerializer + private serializer: RouterStateSerializer, + @Inject(_ROUTER_CONFIG) private config: StoreRouterConfig ) { + this.stateKey = (config && config.stateKey) || this.stateKey; + this.setUpBeforePreactivationHook(); this.setUpStoreStateListener(); this.setUpStateRollbackEvents(); @@ -187,28 +210,28 @@ export class StoreRouterConnectingModule { this.store.subscribe(s => { this.storeState = s; }); - this.store.select('routerReducer').subscribe(() => { + this.store.select(this.stateKey).subscribe(() => { this.navigateIfNeeded(); }); } private shouldDispatchRouterNavigation(): boolean { - if (!this.storeState['routerReducer']) return true; + if (!this.storeState[this.stateKey]) return true; return !this.navigationTriggeredByDispatch; } private navigateIfNeeded(): void { if ( - !this.storeState['routerReducer'] || - !this.storeState['routerReducer'].state + !this.storeState[this.stateKey] || + !this.storeState[this.stateKey].state ) { return; } if (this.dispatchTriggeredByRouter) return; - if (this.router.url !== this.storeState['routerReducer'].state.url) { + if (this.router.url !== this.storeState[this.stateKey].state.url) { this.navigationTriggeredByDispatch = true; - this.router.navigateByUrl(this.storeState['routerReducer'].state.url); + this.router.navigateByUrl(this.storeState[this.stateKey].state.url); } }