feat(router): Allow navigation without updating the URL (#9608)

This commit is contained in:
Brandon 2016-08-04 13:46:09 -05:00 committed by Alex Rickabaugh
parent 2b704f0586
commit 63b82cd730
3 changed files with 64 additions and 8 deletions

View File

@ -46,6 +46,7 @@ export interface NavigationExtras {
fragment?: string; fragment?: string;
preserveQueryParams?: boolean; preserveQueryParams?: boolean;
preserveFragment?: boolean; preserveFragment?: boolean;
skipLocationChange?: boolean;
} }
/** /**
@ -261,17 +262,21 @@ export class Router {
* *
* ``` * ```
* router.navigateByUrl("/team/33/user/11"); * 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 * In opposite to `navigate`, `navigateByUrl` takes a whole URL
* and does not apply any delta to the current one. * and does not apply any delta to the current one.
*/ */
navigateByUrl(url: string|UrlTree): Promise<boolean> { navigateByUrl(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}):
Promise<boolean> {
if (url instanceof UrlTree) { if (url instanceof UrlTree) {
return this.scheduleNavigation(url, false); return this.scheduleNavigation(url, extras);
} else { } else {
const urlTree = this.urlSerializer.parse(url); 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}); * 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 * In opposite to `navigateByUrl`, `navigate` always takes a delta
* that is applied to the current URL. * that is applied to the current URL.
*/ */
navigate(commands: any[], extras: NavigationExtras = {}): Promise<boolean> { navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
return this.scheduleNavigation(this.createUrlTree(commands, extras), false); Promise<boolean> {
return this.scheduleNavigation(this.createUrlTree(commands, extras), extras);
} }
/** /**
@ -319,10 +328,10 @@ export class Router {
} }
} }
private scheduleNavigation(url: UrlTree, preventPushState: boolean): Promise<boolean> { private scheduleNavigation(url: UrlTree, extras: NavigationExtras): Promise<boolean> {
const id = ++this.navigationId; const id = ++this.navigationId;
this.routerEvents.next(new NavigationStart(id, this.serializeUrl(url))); 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 { private setUpLocationChangeListener(): void {

View File

@ -113,6 +113,52 @@ describe('Integration', () => {
expect(location.path()).toEqual('/team/33'); 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', it('should navigate back and forward',
fakeAsync(inject( fakeAsync(inject(
[Router, TestComponentBuilder, Location], [Router, TestComponentBuilder, Location],

View File

@ -106,6 +106,7 @@ export interface NavigationExtras {
preserveQueryParams?: boolean; preserveQueryParams?: boolean;
queryParams?: Params; queryParams?: Params;
relativeTo?: ActivatedRoute; relativeTo?: ActivatedRoute;
skipLocationChange?: boolean;
} }
/** @stable */ /** @stable */
@ -173,7 +174,7 @@ export declare class Router {
initialNavigation(): void; initialNavigation(): void;
isActive(url: string | UrlTree, exact: boolean): boolean; isActive(url: string | UrlTree, exact: boolean): boolean;
navigate(commands: any[], extras?: NavigationExtras): Promise<boolean>; navigate(commands: any[], extras?: NavigationExtras): Promise<boolean>;
navigateByUrl(url: string | UrlTree): Promise<boolean>; navigateByUrl(url: string | UrlTree, extras?: NavigationExtras): Promise<boolean>;
ngOnDestroy(): void; ngOnDestroy(): void;
parseUrl(url: string): UrlTree; parseUrl(url: string): UrlTree;
resetConfig(config: Routes): void; resetConfig(config: Routes): void;