diff --git a/modules/@angular/router/src/directives/router_link.ts b/modules/@angular/router/src/directives/router_link.ts index e4d0cff442..f0f6db524b 100644 --- a/modules/@angular/router/src/directives/router_link.ts +++ b/modules/@angular/router/src/directives/router_link.ts @@ -7,12 +7,14 @@ */ import {LocationStrategy} from '@angular/common'; -import {Directive, HostBinding, HostListener, Input, OnChanges} from '@angular/core'; +import {Directive, HostBinding, HostListener, Input, OnChanges, OnDestroy} from '@angular/core'; +import {Subscription} from 'rxjs/Subscription'; -import {Router} from '../router'; +import {NavigationEnd, Router} from '../router'; import {ActivatedRoute} from '../router_state'; import {UrlTree} from '../url_tree'; + /** * The RouterLink directive lets you link to specific parts of your app. * @@ -93,11 +95,12 @@ export class RouterLink { * @stable */ @Directive({selector: 'a[routerLink]'}) -export class RouterLinkWithHref implements OnChanges { +export class RouterLinkWithHref implements OnChanges, OnDestroy { @Input() target: string; private commands: any[] = []; @Input() queryParams: {[k: string]: any}; @Input() fragment: string; + private subscription: Subscription; // the url displayed on the anchor element. @HostBinding() href: string; @@ -109,7 +112,13 @@ export class RouterLinkWithHref implements OnChanges { */ constructor( private router: Router, private route: ActivatedRoute, - private locationStrategy: LocationStrategy) {} + private locationStrategy: LocationStrategy) { + this.subscription = router.events.subscribe(s => { + if (s instanceof NavigationEnd) { + this.updateTargetUrlAndHref(); + } + }); + } @Input() set routerLink(data: any[]|string) { @@ -121,6 +130,7 @@ export class RouterLinkWithHref implements OnChanges { } ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); } + ngOnDestroy(): any { this.subscription.unsubscribe(); } @HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey']) onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean { diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index d7b29f196c..78ba3c9a01 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -503,6 +503,33 @@ describe('Integration', () => { expect(fixture.debugElement.nativeElement).toHaveText('team 33 { simple, right: }'); }))); + it('should update hrefs when query params change', + fakeAsync( + inject([Router, TestComponentBuilder], (router: Router, tcb: TestComponentBuilder) => { + + @Component({ + selector: 'someRoot', + template: `Link`, + directives: ROUTER_DIRECTIVES + }) + class RootCmpWithLink { + } + + const fixture = createRoot(tcb, router, RootCmpWithLink); + + router.resetConfig([{path: 'home', component: SimpleCmp}]); + + const native = fixture.debugElement.nativeElement.querySelector('a'); + + router.navigateByUrl('/home?q=123'); + advance(fixture); + expect(native.getAttribute('href')).toEqual('/home?q=123'); + + router.navigateByUrl('/home?q=456'); + advance(fixture); + expect(native.getAttribute('href')).toEqual('/home?q=456'); + }))); + it('should support using links on non-a tags', fakeAsync( inject([Router, TestComponentBuilder], (router: Router, tcb: TestComponentBuilder) => { @@ -1154,6 +1181,14 @@ class UserCmp { } } +@Component({ + selector: 'wrapper', + template: ``, + directives: [ROUTER_DIRECTIVES] +}) +class WrapperCmp { +} + @Component({ selector: 'query-cmp', template: `query: {{name | async}} fragment: {{fragment | async}}`, @@ -1192,7 +1227,7 @@ class RelativeLinkInIfCmp { precompile: [ BlankCmp, SimpleCmp, TeamCmp, UserCmp, StringLinkCmp, DummyLinkCmp, AbsoluteLinkCmp, RelativeLinkCmp, DummyLinkWithParentCmp, LinkWithQueryParamsAndFragment, CollectParamsCmp, - QueryParamsAndFragmentCmp, StringLinkButtonCmp + QueryParamsAndFragmentCmp, StringLinkButtonCmp, WrapperCmp ] }) class RootCmp {