diff --git a/modules/@angular/router/src/create_url_tree.ts b/modules/@angular/router/src/create_url_tree.ts
index 6d9cb24b90..d2794d07e5 100644
--- a/modules/@angular/router/src/create_url_tree.ts
+++ b/modules/@angular/router/src/create_url_tree.ts
@@ -42,13 +42,11 @@ function validateCommands(n: NormalizedNavigationCommands): void {
function tree(
oldSegment: UrlSegment, newSegment: UrlSegment, urlTree: UrlTree, queryParams: Params,
fragment: string): UrlTree {
- const q = queryParams ? stringify(queryParams) : urlTree.queryParams;
- const f = fragment ? fragment : urlTree.fragment;
-
if (urlTree.root === oldSegment) {
- return new UrlTree(newSegment, q, f);
+ return new UrlTree(newSegment, stringify(queryParams), fragment);
} else {
- return new UrlTree(replaceSegment(urlTree.root, oldSegment, newSegment), q, f);
+ return new UrlTree(
+ replaceSegment(urlTree.root, oldSegment, newSegment), stringify(queryParams), fragment);
}
}
diff --git a/modules/@angular/router/src/directives/router_link.ts b/modules/@angular/router/src/directives/router_link.ts
index 904e44f0ca..ad26a4f17d 100644
--- a/modules/@angular/router/src/directives/router_link.ts
+++ b/modules/@angular/router/src/directives/router_link.ts
@@ -51,9 +51,15 @@ import {UrlTree} from '../url_tree';
* link to user
component
* ```
- *
* RouterLink will use these to generate this link: `/user/bob#education?debug=true`.
*
+ * You can also tell the directive to preserve the current query params and fragment:
+ *
+ * ```
+ * link to user
+ component
+ * ```
+ *
* @stable
*/
@Directive({selector: ':not(a)[routerLink]'})
@@ -61,6 +67,8 @@ export class RouterLink {
private commands: any[] = [];
@Input() queryParams: {[k: string]: any};
@Input() fragment: string;
+ @Input() preserveQueryParams: boolean;
+ @Input() preserveFragment: boolean;
constructor(
private router: Router, private route: ActivatedRoute,
@@ -85,9 +93,13 @@ export class RouterLink {
}
get urlTree(): UrlTree {
- return this.router.createUrlTree(
- this.commands,
- {relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment});
+ return this.router.createUrlTree(this.commands, {
+ relativeTo: this.route,
+ queryParams: this.queryParams,
+ fragment: this.fragment,
+ preserveQueryParams: toBool(this.preserveQueryParams),
+ preserveFragment: toBool(this.preserveFragment)
+ });
}
}
@@ -101,6 +113,9 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
private commands: any[] = [];
@Input() queryParams: {[k: string]: any};
@Input() fragment: string;
+ @Input() routerLinkOptions: {preserveQueryParams: boolean, preserveFragment: boolean};
+ @Input() preserveQueryParams: boolean;
+ @Input() preserveFragment: boolean;
private subscription: Subscription;
// the url displayed on the anchor element.
@@ -148,12 +163,21 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
}
private updateTargetUrlAndHref(): void {
- this.urlTree = this.router.createUrlTree(
- this.commands,
- {relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment});
+ this.urlTree = this.router.createUrlTree(this.commands, {
+ relativeTo: this.route,
+ queryParams: this.queryParams,
+ fragment: this.fragment,
+ preserveQueryParams: toBool(this.preserveQueryParams),
+ preserveFragment: toBool(this.preserveFragment)
+ });
if (this.urlTree) {
this.href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.urlTree));
}
}
}
+
+function toBool(s?: any): boolean {
+ if (s === '') return true;
+ return !!s;
+}
\ No newline at end of file
diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts
index 913ad39a1a..d00f0ddf40 100644
--- a/modules/@angular/router/src/router.ts
+++ b/modules/@angular/router/src/router.ts
@@ -45,6 +45,8 @@ export interface NavigationExtras {
relativeTo?: ActivatedRoute;
queryParams?: Params;
fragment?: string;
+ preserveQueryParams?: boolean;
+ preserveFragment?: boolean;
}
/**
@@ -227,10 +229,13 @@ export class Router {
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
* ```
*/
- createUrlTree(commands: any[], {relativeTo, queryParams, fragment}: NavigationExtras = {}):
- UrlTree {
+ createUrlTree(
+ commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams,
+ preserveFragment}: NavigationExtras = {}): UrlTree {
const a = relativeTo ? relativeTo : this.routerState.root;
- return createUrlTree(a, this.currentUrlTree, commands, queryParams, fragment);
+ const q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams;
+ const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
+ return createUrlTree(a, this.currentUrlTree, commands, q, f);
}
/**
diff --git a/modules/@angular/router/src/url_tree.ts b/modules/@angular/router/src/url_tree.ts
index 69759449c8..c7db4b6d71 100644
--- a/modules/@angular/router/src/url_tree.ts
+++ b/modules/@angular/router/src/url_tree.ts
@@ -183,7 +183,9 @@ export class DefaultUrlSerializer implements UrlSerializer {
serialize(tree: UrlTree): string {
const segment = `/${serializeSegment(tree.root, true)}`;
const query = serializeQueryParams(tree.queryParams);
- const fragment = tree.fragment !== null ? `#${encodeURIComponent(tree.fragment)}` : '';
+ const fragment = tree.fragment !== null && tree.fragment !== undefined ?
+ `#${encodeURIComponent(tree.fragment)}` :
+ '';
return `${segment}${query}${fragment}`;
}
}
diff --git a/modules/@angular/router/test/create_url_tree.spec.ts b/modules/@angular/router/test/create_url_tree.spec.ts
index 9189e72c42..821d440af4 100644
--- a/modules/@angular/router/test/create_url_tree.spec.ts
+++ b/modules/@angular/router/test/create_url_tree.spec.ts
@@ -182,23 +182,11 @@ describe('createUrlTree', () => {
expect(t.queryParams).toEqual({a: '1'});
});
- it('should reuse old query params when given undefined', () => {
- const p = serializer.parse('/?a=1');
- const t = createRoot(p, [], undefined);
- expect(t.queryParams).toEqual({a: '1'});
- });
-
it('should set fragment', () => {
const p = serializer.parse('/');
const t = createRoot(p, [], {}, 'fragment');
expect(t.fragment).toEqual('fragment');
});
-
- it('should reused old fragment when given undefined', () => {
- const p = serializer.parse('/#fragment');
- const t = createRoot(p, [], undefined, undefined);
- expect(t.fragment).toEqual('fragment');
- });
});
diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts
index fd0c4ea628..9c667d41a7 100644
--- a/modules/@angular/router/test/router.spec.ts
+++ b/modules/@angular/router/test/router.spec.ts
@@ -594,10 +594,9 @@ describe('Integration', () => {
expect(fixture.debugElement.nativeElement).toHaveText('team 33 [ simple, right: ]');
})));
- it('should update hrefs when query params change',
+ it('should not preserve query params and fragment by default',
fakeAsync(
inject([Router, TestComponentBuilder], (router: Router, tcb: TestComponentBuilder) => {
-
@Component({
selector: 'someRoot',
template: `Link`,
@@ -612,15 +611,42 @@ describe('Integration', () => {
const native = fixture.debugElement.nativeElement.querySelector('a');
- router.navigateByUrl('/home?q=123');
+ router.navigateByUrl('/home?q=123#fragment');
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');
+ expect(native.getAttribute('href')).toEqual('/home');
})));
+ it('should update hrefs when query params or fragment 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');
+
+ router.navigateByUrl('/home?q=456#1');
+ advance(fixture);
+ expect(native.getAttribute('href')).toEqual('/home?q=456#1');
+ })));
+
it('should support using links on non-a tags',
fakeAsync(
inject([Router, TestComponentBuilder], (router: Router, tcb: TestComponentBuilder) => {