From 283424f604de07cb67ce7a27511697d00276a110 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Mon, 21 Jan 2019 15:33:18 +0100 Subject: [PATCH] feat(router-store): add routerState to action payload (#1511) --- modules/router-store/spec/integration.spec.ts | 46 +++++++++++++++++++ modules/router-store/src/actions.ts | 40 +++++++++++----- .../router-store/src/router_store_module.ts | 27 +++++++++-- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/modules/router-store/spec/integration.spec.ts b/modules/router-store/spec/integration.spec.ts index 90f9c3a4b5..dcaf4607c5 100644 --- a/modules/router-store/spec/integration.spec.ts +++ b/modules/router-store/spec/integration.spec.ts @@ -6,6 +6,7 @@ import { RouterStateSnapshot, NavigationCancel, NavigationError, + ActivatedRouteSnapshot, } from '@angular/router'; import { Store, ScannedActionsSubject } from '@ngrx/store'; import { filter, first, mapTo, take } from 'rxjs/operators'; @@ -88,6 +89,51 @@ describe('integration spec', () => { }); }); + it('should have the routerState in the payload', (done: any) => { + const actionLog: RouterAction[] = []; + const reducer = (state: string = '', action: RouterAction) => { + switch (action.type) { + case ROUTER_CANCEL: + case ROUTER_ERROR: + case ROUTER_NAVIGATED: + case ROUTER_NAVIGATION: + case ROUTER_REQUEST: + actionLog.push(action); + return state; + default: + return state; + } + }; + + createTestModule({ + reducers: { reducer }, + canActivate: ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ) => state.url !== 'next', + }); + + const router: Router = TestBed.get(Router); + const log = logOfRouterAndActionsAndStore(); + + const hasRouterState = (action: RouterAction) => + !!action.payload.routerState; + + router + .navigateByUrl('/') + .then(() => { + expect(actionLog.filter(hasRouterState).length).toBe(actionLog.length); + }) + .then(() => { + actionLog.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(actionLog.filter(hasRouterState).length).toBe(actionLog.length); + done(); + }); + }); + xit('should support preventing navigation', (done: any) => { const reducer = (state: string = '', action: RouterAction) => { if ( diff --git a/modules/router-store/src/actions.ts b/modules/router-store/src/actions.ts index cbe0675ad7..4f46887d32 100644 --- a/modules/router-store/src/actions.ts +++ b/modules/router-store/src/actions.ts @@ -19,16 +19,21 @@ export const ROUTER_REQUEST = '@ngrx/router-store/request'; /** * Payload of ROUTER_REQUEST */ -export type RouterRequestPayload = { +export type RouterRequestPayload< + T extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { + routerState: T; event: NavigationStart; }; /** * An action dispatched when a router navigation request is fired. */ -export type RouterRequestAction = { +export type RouterRequestAction< + T extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { type: typeof ROUTER_REQUEST; - payload: RouterRequestPayload; + payload: RouterRequestPayload; }; /** @@ -39,7 +44,9 @@ export const ROUTER_NAVIGATION = '@ngrx/router-store/navigation'; /** * Payload of ROUTER_NAVIGATION. */ -export type RouterNavigationPayload = { +export type RouterNavigationPayload< + T extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { routerState: T; event: RoutesRecognized; }; @@ -62,7 +69,10 @@ export const ROUTER_CANCEL = '@ngrx/router-store/cancel'; /** * Payload of ROUTER_CANCEL. */ -export type RouterCancelPayload = { +export type RouterCancelPayload< + T, + V extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { routerState: V; storeState: T; event: NavigationCancel; @@ -87,7 +97,10 @@ export const ROUTER_ERROR = '@ngrx/router-store/error'; /** * Payload of ROUTER_ERROR. */ -export type RouterErrorPayload = { +export type RouterErrorPayload< + T, + V extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { routerState: V; storeState: T; event: NavigationError; @@ -112,16 +125,21 @@ export const ROUTER_NAVIGATED = '@ngrx/router-store/navigated'; /** * Payload of ROUTER_NAVIGATED. */ -export type RouterNavigatedPayload = { +export type RouterNavigatedPayload< + T extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { + routerState: T; event: NavigationEnd; }; /** * An action dispatched after navigation has ended and new route is active. */ -export type RouterNavigatedAction = { +export type RouterNavigatedAction< + T extends BaseRouterStoreState = SerializedRouterStateSnapshot +> = { type: typeof ROUTER_NAVIGATED; - payload: RouterNavigatedPayload; + payload: RouterNavigatedPayload; }; /** @@ -131,8 +149,8 @@ export type RouterAction< T, V extends BaseRouterStoreState = SerializedRouterStateSnapshot > = - | RouterRequestAction + | RouterRequestAction | RouterNavigationAction | RouterCancelAction | RouterErrorAction - | RouterNavigatedAction; + | RouterNavigatedAction; diff --git a/modules/router-store/src/router_store_module.ts b/modules/router-store/src/router_store_module.ts index 094972d3e3..fc4376fff3 100644 --- a/modules/router-store/src/router_store_module.ts +++ b/modules/router-store/src/router_store_module.ts @@ -13,6 +13,7 @@ import { RoutesRecognized, NavigationStart, Event, + RouterEvent, } from '@angular/router'; import { select, Selector, Store } from '@ngrx/store'; import { withLatestFrom } from 'rxjs/operators'; @@ -51,6 +52,12 @@ export interface StoreRouterConfig< navigationActionTiming?: NavigationActionTiming; } +interface StoreRouterActionPayload { + event: RouterEvent; + routerState?: SerializedRouterStateSnapshot; + storeState?: any; +} + export enum NavigationActionTiming { PreActivation = 1, PostActivation = 2, @@ -281,7 +288,6 @@ export class StoreRouterConnectingModule { private dispatchRouterCancel(event: NavigationCancel): void { this.dispatchRouterAction(ROUTER_CANCEL, { - routerState: this.routerState!, storeState: this.storeState, event, }); @@ -289,20 +295,31 @@ export class StoreRouterConnectingModule { private dispatchRouterError(event: NavigationError): void { this.dispatchRouterAction(ROUTER_ERROR, { - routerState: this.routerState!, storeState: this.storeState, event: new NavigationError(event.id, event.url, `${event}`), }); } private dispatchRouterNavigated(event: NavigationEnd): void { - this.dispatchRouterAction(ROUTER_NAVIGATED, { event }); + const routerState = this.serializer.serialize( + this.router.routerState.snapshot + ); + this.dispatchRouterAction(ROUTER_NAVIGATED, { event, routerState }); } - private dispatchRouterAction(type: string, payload: any): void { + private dispatchRouterAction( + type: string, + payload: StoreRouterActionPayload + ): void { this.trigger = RouterTrigger.ROUTER; try { - this.store.dispatch({ type, payload }); + this.store.dispatch({ + type, + payload: { + routerState: this.routerState, + ...payload, + }, + }); } finally { this.trigger = RouterTrigger.NONE; }