diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 7258fcddfb..e1194a24fd 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -46,6 +46,7 @@ export interface NavigationExtras { fragment?: string; preserveQueryParams?: boolean; preserveFragment?: boolean; + skipLocationChange?: boolean; } /** @@ -261,17 +262,21 @@ export class Router { * * ``` * router.navigateByUrl("/team/33/user/11"); + * + * // Navigate without updating the URL + * router.navigateByUrl("/team/33/user/11", { skipLocationChange: true }); * ``` * * In opposite to `navigate`, `navigateByUrl` takes a whole URL * and does not apply any delta to the current one. */ - navigateByUrl(url: string|UrlTree): Promise { + navigateByUrl(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}): + Promise { if (url instanceof UrlTree) { - return this.scheduleNavigation(url, false); + return this.scheduleNavigation(url, extras); } else { const urlTree = this.urlSerializer.parse(url); - return this.scheduleNavigation(urlTree, false); + return this.scheduleNavigation(urlTree, extras); } } @@ -288,13 +293,17 @@ export class Router { * * ``` * router.navigate(['team', 33, 'team', '11], {relativeTo: route}); + * + * // Navigate without updating the URL + * router.navigate(['team', 33, 'team', '11], {relativeTo: route, skipLocationChange: true }); * ``` * * In opposite to `navigateByUrl`, `navigate` always takes a delta * that is applied to the current URL. */ - navigate(commands: any[], extras: NavigationExtras = {}): Promise { - return this.scheduleNavigation(this.createUrlTree(commands, extras), false); + navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}): + Promise { + return this.scheduleNavigation(this.createUrlTree(commands, extras), extras); } /** @@ -319,10 +328,10 @@ export class Router { } } - private scheduleNavigation(url: UrlTree, preventPushState: boolean): Promise { + private scheduleNavigation(url: UrlTree, extras: NavigationExtras): Promise { const id = ++this.navigationId; this.routerEvents.next(new NavigationStart(id, this.serializeUrl(url))); - return Promise.resolve().then((_) => this.runNavigate(url, preventPushState, id)); + return Promise.resolve().then((_) => this.runNavigate(url, extras.skipLocationChange, id)); } private setUpLocationChangeListener(): void { diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index 6f3833e51f..4b3a0e8431 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -113,6 +113,52 @@ describe('Integration', () => { expect(location.path()).toEqual('/team/33'); }))); + it('should skip location update when using NavigationExtras.skipLocationChange with navigateByUrl', + fakeAsync(inject( + [Router, TestComponentBuilder, Location], + (router: Router, tcb: TestComponentBuilder, location: Location) => { + const fixture = tcb.createFakeAsync(RootCmp); + advance(fixture); + + router.resetConfig([{path: 'team/:id', component: TeamCmp}]); + + router.navigateByUrl('/team/22'); + advance(fixture); + expect(location.path()).toEqual('/team/22'); + + expect(fixture.debugElement.nativeElement).toHaveText('team 22 [ , right: ]'); + + router.navigateByUrl('/team/33', {skipLocationChange: true}); + advance(fixture); + + expect(location.path()).toEqual('/team/22'); + + expect(fixture.debugElement.nativeElement).toHaveText('team 33 [ , right: ]'); + }))); + + it('should skip location update when using NavigationExtras.skipLocationChange with navigate', + fakeAsync(inject( + [Router, TestComponentBuilder, Location], + (router: Router, tcb: TestComponentBuilder, location: Location) => { + const fixture = tcb.createFakeAsync(RootCmp); + advance(fixture); + + router.resetConfig([{path: 'team/:id', component: TeamCmp}]); + + router.navigate(['/team/22']); + advance(fixture); + expect(location.path()).toEqual('/team/22'); + + expect(fixture.debugElement.nativeElement).toHaveText('team 22 [ , right: ]'); + + router.navigate(['/team/33'], {skipLocationChange: true}); + advance(fixture); + + expect(location.path()).toEqual('/team/22'); + + expect(fixture.debugElement.nativeElement).toHaveText('team 33 [ , right: ]'); + }))); + it('should navigate back and forward', fakeAsync(inject( [Router, TestComponentBuilder, Location], diff --git a/tools/public_api_guard/router/index.d.ts b/tools/public_api_guard/router/index.d.ts index 6ee3758afd..f9aa9ac457 100644 --- a/tools/public_api_guard/router/index.d.ts +++ b/tools/public_api_guard/router/index.d.ts @@ -106,6 +106,7 @@ export interface NavigationExtras { preserveQueryParams?: boolean; queryParams?: Params; relativeTo?: ActivatedRoute; + skipLocationChange?: boolean; } /** @stable */ @@ -173,7 +174,7 @@ export declare class Router { initialNavigation(): void; isActive(url: string | UrlTree, exact: boolean): boolean; navigate(commands: any[], extras?: NavigationExtras): Promise; - navigateByUrl(url: string | UrlTree): Promise; + navigateByUrl(url: string | UrlTree, extras?: NavigationExtras): Promise; ngOnDestroy(): void; parseUrl(url: string): UrlTree; resetConfig(config: Routes): void;