From ad20d7d260845d16cae2969c3cda968e3615397e Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 17 Nov 2016 11:58:12 -0800 Subject: [PATCH] fix(router): guards restor an incorrect url when used with skipLocationChange Closes #12825 --- modules/@angular/router/src/router.ts | 9 +++++--- .../@angular/router/test/integration.spec.ts | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 5aea6eeef5..96d8a7d6ae 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -299,6 +299,7 @@ type NavigationParams = { export class Router { private currentUrlTree: UrlTree; private rawUrlTree: UrlTree; + private currentUrlTreeStoredInLocation: UrlTree; private navigations: BehaviorSubject = new BehaviorSubject(null); @@ -716,6 +717,7 @@ export class Router { let navigationIsSuccessful: boolean; const storedState = this.currentRouterState; const storedUrl = this.currentUrlTree; + const storedUrlInLocation = this.currentUrlTreeStoredInLocation; routerState$ .forEach(({appliedUrl, state, shouldActivate}: any) => { @@ -726,6 +728,8 @@ export class Router { this.currentUrlTree = appliedUrl; this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl); + this.currentUrlTreeStoredInLocation = + shouldPreventPushState ? this.currentUrlTreeStoredInLocation : this.rawUrlTree; this.currentRouterState = state; @@ -774,14 +778,13 @@ export class Router { this.currentRouterState = storedState; this.currentUrlTree = storedUrl; this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl); - this.location.replaceState(this.serializeUrl(this.rawUrlTree)); + this.location.replaceState(this.serializeUrl(storedUrlInLocation)); }); }); } private resetUrlToCurrentUrlTree(): void { - const path = this.urlSerializer.serialize(this.rawUrlTree); - this.location.replaceState(path); + this.location.replaceState(this.urlSerializer.serialize(this.currentUrlTreeStoredInLocation)); } } diff --git a/modules/@angular/router/test/integration.spec.ts b/modules/@angular/router/test/integration.spec.ts index e81c74cc74..534785c85b 100644 --- a/modules/@angular/router/test/integration.spec.ts +++ b/modules/@angular/router/test/integration.spec.ts @@ -1532,6 +1532,27 @@ describe('Integration', () => { expect(location.path()).toEqual('/main/component1'); }))); + it('should respect skipLocationChange when guards cancel navigations', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const fixture = createRoot(router, RootCmp); + + router.resetConfig([ + {path: 'component1', component: SimpleCmp}, + {path: 'component2', component: SimpleCmp, canDeactivate: ['alwaysFalse']} + ]); + + router.navigateByUrl('/component1'); // initial state + advance(fixture); + + router.navigateByUrl('/component2', {skipLocationChange: true}); + advance(fixture); + expect(location.path()).toEqual('/component1'); + + location.back(); + advance(fixture); + + expect(location.path()).toEqual('/component1'); + }))); }); describe('should work when given a class', () => {