diff --git a/modules/@angular/router/src/directives/router_link.ts b/modules/@angular/router/src/directives/router_link.ts index fac4328f28..a64da76336 100644 --- a/modules/@angular/router/src/directives/router_link.ts +++ b/modules/@angular/router/src/directives/router_link.ts @@ -2,7 +2,8 @@ import { Directive, HostListener, HostBinding, - Input + Input, + OnChanges } from '@angular/core'; import {Router} from '../router'; import {ActivatedRoute} from '../router_state'; @@ -33,9 +34,11 @@ import {ActivatedRoute} from '../router_state'; * And if the segment begins with `../`, the router will go up one level. */ @Directive({selector: '[routerLink]'}) -export class RouterLink { +export class RouterLink implements OnChanges { @Input() target: string; private commands: any[] = []; + @Input() queryParams: {[k:string]:any}; + @Input() fragment: string; // the url displayed on the anchor element. @HostBinding() href: string; @@ -48,25 +51,36 @@ export class RouterLink { @Input() set routerLink(data: any[] | string) { if (Array.isArray(data)) { - this.commands = data; + this.commands = data; } else { this.commands = [data]; } + } + + ngOnChanges(changes:{}):any { this.updateTargetUrlAndHref(); } - + @HostListener("click") onClick(): boolean { // If no target, or if target is _self, prevent default browser behavior if (!(typeof this.target === "string") || this.target == '_self') { - this.router.navigate(this.commands, {relativeTo: this.route}); + this.router.navigate(this.commands, { + relativeTo: this.route, + queryParameters: this.queryParams, + fragment: this.fragment + }); return false; } return true; } private updateTargetUrlAndHref(): void { - const tree = this.router.createUrlTree(this.commands, {relativeTo: this.route}); + const tree = this.router.createUrlTree(this.commands, { + relativeTo: this.route, + queryParameters: this.queryParams, + fragment: this.fragment + }); if (tree) { this.href = this.router.serializeUrl(tree); } diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 3c26f43ff8..da0df2a1b8 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -193,7 +193,7 @@ export class Router { navigate(commands: any[], extras: NavigationExtras = {}): Promise { return this.scheduleNavigation(this.createUrlTree(commands, extras), false); } - + /** * Serializes a {@link UrlTree} into a string. */ diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index 92b2010325..24c9ecee3e 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -36,8 +36,11 @@ describe("Integration", () => { {provide: Location, useClass: SpyLocation}, { provide: Router, - useFactory: (resolver, urlSerializer, outletMap, location, injector) => - new Router(RootCmp, resolver, urlSerializer, outletMap, location, injector, config), + useFactory: (resolver, urlSerializer, outletMap, location, injector) => { + const r = new Router(RootCmp, resolver, urlSerializer, outletMap, location, injector, config); + r.initialNavigation(); + return r; + }, deps: [ComponentResolver, UrlSerializer, RouterOutletMap, Location, Injector] }, {provide: ActivatedRoute, useFactory: (r) => r.routerState.root, deps: [Router]}, @@ -389,6 +392,32 @@ describe("Integration", () => { advance(fixture); expect(fixture.debugElement.nativeElement).toHaveText('link'); }))); + + it("should support query params and fragments", + fakeAsync(inject([Router, Location, TestComponentBuilder], (router, location, tcb) => { + router.resetConfig([ + { path: 'team/:id', component: TeamCmp, children: [ + { path: 'link', component: LinkWithQueryParamsAndFragment }, + { path: 'simple', component: SimpleCmp } + ] } + ]); + + const fixture = tcb.createFakeAsync(RootCmp); + advance(fixture); + + router.navigateByUrl('/team/22/link'); + advance(fixture); + + const native = fixture.debugElement.nativeElement.querySelector("a"); + expect(native.getAttribute("href")).toEqual("/team/22/simple?q=1#f"); + native.click(); + advance(fixture); + + expect(fixture.debugElement.nativeElement) + .toHaveText('team 22 { simple, right: }'); + + expect(location.path()).toEqual('/team/22/simple?q=1#f'); + }))); }); describe("guards", () => { @@ -603,6 +632,13 @@ class AbsoluteLinkCmp {} }) class RelativeLinkCmp {} +@Component({ + selector: 'link-cmp', + template: `link`, + directives: ROUTER_DIRECTIVES +}) +class LinkWithQueryParamsAndFragment {} + @Component({ selector: 'simple-cmp', template: `simple`,