From f562cbf86ca57fdcce5e2c77e51940bb19f86427 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Fri, 2 Dec 2016 13:34:05 -0800 Subject: [PATCH] fix(router): fix skipLocationChanges on RouterLink directives fixes #13156 --- .../router/src/directives/router_link.ts | 22 +++++----- .../@angular/router/test/integration.spec.ts | 44 ++++++++++++++++--- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/modules/@angular/router/src/directives/router_link.ts b/modules/@angular/router/src/directives/router_link.ts index e8bca982a1..28f2bba0bf 100644 --- a/modules/@angular/router/src/directives/router_link.ts +++ b/modules/@angular/router/src/directives/router_link.ts @@ -102,7 +102,8 @@ export class RouterLink { @HostListener('click', []) onClick(): boolean { - this.router.navigateByUrl(this.urlTree); + const extras = {skipLocationChange: attrBoolValue(this.skipLocationChange)}; + this.router.navigateByUrl(this.urlTree, extras); return true; } @@ -111,10 +112,9 @@ export class RouterLink { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment, - preserveQueryParams: toBool(this.preserveQueryParams), - preserveFragment: toBool(this.preserveFragment), - skipLocationChange: toBool(this.skipLocationChange), - replaceUrl: toBool(this.replaceUrl), + preserveQueryParams: attrBoolValue(this.preserveQueryParams), + preserveFragment: attrBoolValue(this.preserveFragment), + replaceUrl: attrBoolValue(this.replaceUrl), }); } } @@ -176,7 +176,8 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { return true; } - this.router.navigateByUrl(this.urlTree); + const extras = {skipLocationChange: attrBoolValue(this.skipLocationChange)}; + this.router.navigateByUrl(this.urlTree, extras); return false; } @@ -189,14 +190,13 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment, - preserveQueryParams: toBool(this.preserveQueryParams), - preserveFragment: toBool(this.preserveFragment), - skipLocationChange: toBool(this.skipLocationChange), - replaceUrl: toBool(this.replaceUrl), + preserveQueryParams: attrBoolValue(this.preserveQueryParams), + preserveFragment: attrBoolValue(this.preserveFragment), + replaceUrl: attrBoolValue(this.replaceUrl), }); } } -function toBool(s: any): boolean { +function attrBoolValue(s: any): boolean { return s === '' || !!s; } diff --git a/modules/@angular/router/test/integration.spec.ts b/modules/@angular/router/test/integration.spec.ts index d4013eb6e5..0fb2a569fc 100644 --- a/modules/@angular/router/test/integration.spec.ts +++ b/modules/@angular/router/test/integration.spec.ts @@ -7,8 +7,9 @@ */ import {CommonModule, Location} from '@angular/common'; -import {Component, Injector, NgModule, NgModuleFactoryLoader} from '@angular/core'; -import {ComponentFixture, TestBed, async, fakeAsync, inject, tick} from '@angular/core/testing'; +import {Component, NgModule, NgModuleFactoryLoader} from '@angular/core'; +import {ComponentFixture, TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; +import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/matchers'; import {Observable} from 'rxjs/Observable'; import {map} from 'rxjs/operator/map'; @@ -18,7 +19,6 @@ import {RouterPreloader} from '../src/router_preloader'; import {forEach} from '../src/utils/collection'; import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing'; - describe('Integration', () => { beforeEach(() => { TestBed.configureTestingModule({ @@ -909,6 +909,37 @@ describe('Integration', () => { }); describe('router links', () => { + it('should support skipping location update for anchor router links', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const fixture = TestBed.createComponent(RootCmp); + advance(fixture); + + router.resetConfig([{path: 'team/:id', component: TeamCmp}]); + + router.navigateByUrl('/team/22'); + advance(fixture); + expect(location.path()).toEqual('/team/22'); + expect(fixture.nativeElement).toHaveText('team 22 [ , right: ]'); + + const teamCmp = fixture.debugElement.childNodes[1].componentInstance; + + teamCmp.routerLink = ['/team/0']; + advance(fixture); + const anchor = fixture.debugElement.query(By.css('a')).nativeElement; + anchor.click(); + advance(fixture); + expect(fixture.nativeElement).toHaveText('team 0 [ , right: ]'); + expect(location.path()).toEqual('/team/22'); + + teamCmp.routerLink = ['/team/1']; + advance(fixture); + const button = fixture.debugElement.query(By.css('button')).nativeElement; + button.click(); + advance(fixture); + expect(fixture.nativeElement).toHaveText('team 1 [ , right: ]'); + expect(location.path()).toEqual('/team/22'); + }))); + it('should support string router links', fakeAsync(inject([Router], (router: Router) => { const fixture = createRoot(router, RootCmp); @@ -2591,12 +2622,15 @@ class BlankCmp { @Component({ selector: 'team-cmp', - template: - `team {{id | async}} [ , right: ]` + template: `team {{id | async}} ` + + `[ , right: ]` + + `` + + `` }) class TeamCmp { id: Observable; recordedParams: Params[] = []; + routerLink = ['.']; constructor(public route: ActivatedRoute) { this.id = map.call(route.params, (p: any) => p['id']);