From c87c3bec93b7d5de7251bf182ae76c83e38d8329 Mon Sep 17 00:00:00 2001 From: evan Liu Date: Wed, 25 Jan 2017 17:33:13 +0800 Subject: [PATCH] feat(router): deprecate preserveQueryParams,add queryParamsHandling (#14095) PR Close #14095 --- modules/@angular/router/src/config.ts | 7 +++ .../router/src/directives/router_link.ts | 45 ++++++++++++++++--- modules/@angular/router/src/router.ts | 39 ++++++++++++++-- .../@angular/router/test/integration.spec.ts | 44 ++++++++++++++++++ tools/public_api_guard/router/index.d.ts | 7 ++- 5 files changed, 131 insertions(+), 11 deletions(-) diff --git a/modules/@angular/router/src/config.ts b/modules/@angular/router/src/config.ts index dc68e60ced..4dd00be40b 100644 --- a/modules/@angular/router/src/config.ts +++ b/modules/@angular/router/src/config.ts @@ -320,6 +320,13 @@ export type LoadChildrenCallback = () => */ export type LoadChildren = string | LoadChildrenCallback; +/** + * @whatItDoes The type of `queryParamsHandling`. + * See {@link RouterLink} for more details. + * @stable + */ +export type QueryParamsHandling = 'merge' | 'preserve' | ''; + /** * See {@link Routes} for more details. * @stable diff --git a/modules/@angular/router/src/directives/router_link.ts b/modules/@angular/router/src/directives/router_link.ts index fe8469de70..5a84060bd5 100644 --- a/modules/@angular/router/src/directives/router_link.ts +++ b/modules/@angular/router/src/directives/router_link.ts @@ -7,9 +7,10 @@ */ import {LocationStrategy} from '@angular/common'; -import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, OnChanges, OnDestroy, Renderer} from '@angular/core'; +import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, OnChanges, OnDestroy, Renderer, isDevMode} from '@angular/core'; import {Subscription} from 'rxjs/Subscription'; +import {QueryParamsHandling} from '../config'; import {NavigationEnd, Router} from '../router'; import {ActivatedRoute} from '../router_state'; import {UrlTree} from '../url_tree'; @@ -59,12 +60,26 @@ import {UrlTree} from '../url_tree'; * * You can also tell the directive to preserve the current query params and fragment: * + * deprecated, use `queryParamsHandling` instead + * * ``` * * link to user component * * ``` * + * You can tell the directive to how to handle queryParams, available options are: + * - 'merge' merge the queryParams into the current queryParams + * - 'preserve' prserve the current queryParams + * - default / '' use the queryParams only + * same options for {@link NavigationExtras.queryParamsHandling} + * + * ``` + * + * link to user component + * + * ``` + * * The router link directive always treats the provided input as a delta to the current url. * * For instance, if the current url is `/user/(box//aux:team)`. @@ -82,11 +97,12 @@ import {UrlTree} from '../url_tree'; export class RouterLink { @Input() queryParams: {[k: string]: any}; @Input() fragment: string; - @Input() preserveQueryParams: boolean; + @Input() queryParamsHandling: QueryParamsHandling; @Input() preserveFragment: boolean; @Input() skipLocationChange: boolean; @Input() replaceUrl: boolean; private commands: any[] = []; + private preserve: boolean; constructor( private router: Router, private route: ActivatedRoute, @@ -105,6 +121,14 @@ export class RouterLink { } } + @Input() + set preserveQueryParams(value: boolean) { + if (isDevMode() && console && console.warn) { + console.warn('preserveQueryParams is deprecated!, use queryParamsHandling instead.'); + } + this.preserve = value; + } + @HostListener('click') onClick(): boolean { const extras = { @@ -120,7 +144,8 @@ export class RouterLink { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment, - preserveQueryParams: attrBoolValue(this.preserveQueryParams), + preserveQueryParams: attrBoolValue(this.preserve), + queryParamsHandling: this.queryParamsHandling, preserveFragment: attrBoolValue(this.preserveFragment), }); } @@ -140,12 +165,13 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { @HostBinding('attr.target') @Input() target: string; @Input() queryParams: {[k: string]: any}; @Input() fragment: string; - @Input() preserveQueryParams: boolean; + @Input() queryParamsHandling: QueryParamsHandling; @Input() preserveFragment: boolean; @Input() skipLocationChange: boolean; @Input() replaceUrl: boolean; private commands: any[] = []; private subscription: Subscription; + private preserve: boolean; // the url displayed on the anchor element. @HostBinding() href: string; @@ -169,6 +195,14 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { } } + @Input() + set preserveQueryParams(value: boolean) { + if (isDevMode() && console && console.warn) { + console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.'); + } + this.preserve = value; + } + ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); } ngOnDestroy(): any { this.subscription.unsubscribe(); } @@ -199,7 +233,8 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment, - preserveQueryParams: attrBoolValue(this.preserveQueryParams), + preserveQueryParams: attrBoolValue(this.preserve), + queryParamsHandling: this.queryParamsHandling, preserveFragment: attrBoolValue(this.preserveFragment), }); } diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index a7a8faef67..7c9cc789f6 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -7,7 +7,7 @@ */ import {Location} from '@angular/common'; -import {Compiler, ComponentFactoryResolver, Injector, NgModuleFactoryLoader, ReflectiveInjector, Type} from '@angular/core'; +import {Compiler, ComponentFactoryResolver, Injector, NgModuleFactoryLoader, ReflectiveInjector, Type, isDevMode} from '@angular/core'; import {BehaviorSubject} from 'rxjs/BehaviorSubject'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; @@ -22,7 +22,7 @@ import {mergeMap} from 'rxjs/operator/mergeMap'; import {reduce} from 'rxjs/operator/reduce'; import {applyRedirects} from './apply_redirects'; -import {ResolveData, Routes, validateConfig} from './config'; +import {QueryParamsHandling, ResolveData, Routes, validateConfig} from './config'; import {createRouterState} from './create_router_state'; import {createUrlTree} from './create_url_tree'; import {RouterOutlet} from './directives/router_outlet'; @@ -102,12 +102,26 @@ export interface NavigationExtras { /** * Preserves the query parameters for the next navigation. * + * deprecated, use `queryParamsHandling` instead + * * ``` * // Preserve query params from /results?page=1 to /view?page=1 * this.router.navigate(['/view'], { preserveQueryParams: true }); * ``` + * + * @deprecated */ preserveQueryParams?: boolean; + + /** + * config strategy to handle the query parameters for the next navigation. + * + * ``` + * // from /results?page=1 to /view?page=1&page=2 + * this.router.navigate(['/view'], { queryParams: { page: 2 }, queryParamsHandling: "merge" }); + * ``` + */ + queryParamsHandling?: QueryParamsHandling; /** * Preserves the fragment for the next navigation * @@ -465,11 +479,28 @@ export class Router { * ``` */ createUrlTree( - commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, + commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}: NavigationExtras = {}): UrlTree { + if (isDevMode() && preserveQueryParams && console && console.warn) { + console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.'); + } const a = relativeTo || this.routerState.root; - const q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams; const f = preserveFragment ? this.currentUrlTree.fragment : fragment; + let q: Params = null; + if (queryParamsHandling) { + switch (queryParamsHandling) { + case 'merge': + q = merge(this.currentUrlTree.queryParams, queryParams); + break; + case 'preserve': + q = this.currentUrlTree.queryParams; + break; + default: + q = queryParams; + } + } else { + q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams; + } return createUrlTree(a, this.currentUrlTree, commands, q, f); } diff --git a/modules/@angular/router/test/integration.spec.ts b/modules/@angular/router/test/integration.spec.ts index c7ab7cdfbc..70331c2896 100644 --- a/modules/@angular/router/test/integration.spec.ts +++ b/modules/@angular/router/test/integration.spec.ts @@ -1100,6 +1100,50 @@ describe('Integration', () => { expect(native.getAttribute('href')).toEqual('/home?q=456#1'); })); + it('should correctly use the preserve strategy', fakeAsync(() => { + + @Component({ + selector: 'someRoot', + template: + `Link` + }) + class RootCmpWithLink { + } + TestBed.configureTestingModule({declarations: [RootCmpWithLink]}); + const router: Router = TestBed.get(Router); + const fixture = createRoot(router, RootCmpWithLink); + + router.resetConfig([{path: 'home', component: SimpleCmp}]); + + const native = fixture.nativeElement.querySelector('a'); + + router.navigateByUrl('/home?a=123'); + advance(fixture); + expect(native.getAttribute('href')).toEqual('/home?a=123'); + })); + + it('should correctly use the merge strategy', fakeAsync(() => { + + @Component({ + selector: 'someRoot', + template: + `Link` + }) + class RootCmpWithLink { + } + TestBed.configureTestingModule({declarations: [RootCmpWithLink]}); + const router: Router = TestBed.get(Router); + const fixture = createRoot(router, RootCmpWithLink); + + router.resetConfig([{path: 'home', component: SimpleCmp}]); + + const native = fixture.nativeElement.querySelector('a'); + + router.navigateByUrl('/home?a=123'); + advance(fixture); + expect(native.getAttribute('href')).toEqual('/home?a=123&q=456'); + })); + it('should support using links on non-a tags', fakeAsync(inject([Router], (router: Router) => { const fixture = createRoot(router, RootCmp); diff --git a/tools/public_api_guard/router/index.d.ts b/tools/public_api_guard/router/index.d.ts index 680d663e1d..d1532d5484 100644 --- a/tools/public_api_guard/router/index.d.ts +++ b/tools/public_api_guard/router/index.d.ts @@ -127,8 +127,9 @@ export declare class NavigationError { export interface NavigationExtras { fragment?: string; preserveFragment?: boolean; - preserveQueryParams?: boolean; + /** @deprecated */ preserveQueryParams?: boolean; queryParams?: Params; + queryParamsHandling?: QueryParamsHandling; relativeTo?: ActivatedRoute; replaceUrl?: boolean; skipLocationChange?: boolean; @@ -209,7 +210,7 @@ export declare class Router { url: string; urlHandlingStrategy: UrlHandlingStrategy; constructor(rootComponentType: Type, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes); - createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, preserveFragment}?: NavigationExtras): UrlTree; + createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}?: NavigationExtras): UrlTree; dispose(): void; initialNavigation(): void; isActive(url: string | UrlTree, exact: boolean): boolean; @@ -245,6 +246,7 @@ export declare class RouterLink { queryParams: { [k: string]: any; }; + queryParamsHandling: QueryParamsHandling; replaceUrl: boolean; routerLink: any[] | string; skipLocationChange: boolean; @@ -277,6 +279,7 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy { queryParams: { [k: string]: any; }; + queryParamsHandling: QueryParamsHandling; replaceUrl: boolean; routerLink: any[] | string; skipLocationChange: boolean;