Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Aug 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 16 additions & 7 deletions modules/@angular/router/src/router.ts
Expand Up @@ -46,6 +46,7 @@ export interface NavigationExtras {
fragment?: string;
preserveQueryParams?: boolean;
preserveFragment?: boolean;
skipLocationChange?: boolean;
}

/**
Expand Down Expand Up @@ -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<boolean> {
navigateByUrl(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}):
Promise<boolean> {
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);
}
}

Expand All @@ -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<boolean> {
return this.scheduleNavigation(this.createUrlTree(commands, extras), false);
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
Promise<boolean> {
return this.scheduleNavigation(this.createUrlTree(commands, extras), extras);
}

/**
Expand All @@ -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;
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 {
Expand Down
46 changes: 46 additions & 0 deletions modules/@angular/router/test/router.spec.ts
Expand Up @@ -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],
Expand Down
3 changes: 2 additions & 1 deletion tools/public_api_guard/router/index.d.ts
Expand Up @@ -106,6 +106,7 @@ export interface NavigationExtras {
preserveQueryParams?: boolean;
queryParams?: Params;
relativeTo?: ActivatedRoute;
skipLocationChange?: boolean;
}

/** @stable */
Expand Down Expand Up @@ -173,7 +174,7 @@ export declare class Router {
initialNavigation(): void;
isActive(url: string | UrlTree, exact: boolean): boolean;
navigate(commands: any[], extras?: NavigationExtras): Promise<boolean>;
navigateByUrl(url: string | UrlTree): Promise<boolean>;
navigateByUrl(url: string | UrlTree, extras?: NavigationExtras): Promise<boolean>;
ngOnDestroy(): void;
parseUrl(url: string): UrlTree;
resetConfig(config: Routes): void;
Expand Down