feat(router): deprecate preserveQueryParams,add queryParamsHandling (#14095)
PR Close #14095
This commit is contained in:
parent
2ffa1a71aa
commit
c87c3bec93
|
@ -320,6 +320,13 @@ export type LoadChildrenCallback = () =>
|
||||||
*/
|
*/
|
||||||
export type LoadChildren = string | 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.
|
* See {@link Routes} for more details.
|
||||||
* @stable
|
* @stable
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LocationStrategy} from '@angular/common';
|
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 {Subscription} from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
import {QueryParamsHandling} from '../config';
|
||||||
import {NavigationEnd, Router} from '../router';
|
import {NavigationEnd, Router} from '../router';
|
||||||
import {ActivatedRoute} from '../router_state';
|
import {ActivatedRoute} from '../router_state';
|
||||||
import {UrlTree} from '../url_tree';
|
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:
|
* You can also tell the directive to preserve the current query params and fragment:
|
||||||
*
|
*
|
||||||
|
* deprecated, use `queryParamsHandling` instead
|
||||||
|
*
|
||||||
* ```
|
* ```
|
||||||
* <a [routerLink]="['/user/bob']" preserveQueryParams preserveFragment>
|
* <a [routerLink]="['/user/bob']" preserveQueryParams preserveFragment>
|
||||||
* link to user component
|
* link to user component
|
||||||
* </a>
|
* </a>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* 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}
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* <a [routerLink]="['/user/bob']" [queryParams]="{debug: true}" queryParamsHandling="merge">
|
||||||
|
* link to user component
|
||||||
|
* </a>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
* The router link directive always treats the provided input as a delta to the current url.
|
* 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)`.
|
* For instance, if the current url is `/user/(box//aux:team)`.
|
||||||
|
@ -82,11 +97,12 @@ import {UrlTree} from '../url_tree';
|
||||||
export class RouterLink {
|
export class RouterLink {
|
||||||
@Input() queryParams: {[k: string]: any};
|
@Input() queryParams: {[k: string]: any};
|
||||||
@Input() fragment: string;
|
@Input() fragment: string;
|
||||||
@Input() preserveQueryParams: boolean;
|
@Input() queryParamsHandling: QueryParamsHandling;
|
||||||
@Input() preserveFragment: boolean;
|
@Input() preserveFragment: boolean;
|
||||||
@Input() skipLocationChange: boolean;
|
@Input() skipLocationChange: boolean;
|
||||||
@Input() replaceUrl: boolean;
|
@Input() replaceUrl: boolean;
|
||||||
private commands: any[] = [];
|
private commands: any[] = [];
|
||||||
|
private preserve: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router, private route: ActivatedRoute,
|
private router: Router, private route: ActivatedRoute,
|
||||||
|
@ -105,6 +121,14 @@ export class RouterLink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set preserveQueryParams(value: boolean) {
|
||||||
|
if (isDevMode() && <any>console && <any>console.warn) {
|
||||||
|
console.warn('preserveQueryParams is deprecated!, use queryParamsHandling instead.');
|
||||||
|
}
|
||||||
|
this.preserve = value;
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('click')
|
@HostListener('click')
|
||||||
onClick(): boolean {
|
onClick(): boolean {
|
||||||
const extras = {
|
const extras = {
|
||||||
|
@ -120,7 +144,8 @@ export class RouterLink {
|
||||||
relativeTo: this.route,
|
relativeTo: this.route,
|
||||||
queryParams: this.queryParams,
|
queryParams: this.queryParams,
|
||||||
fragment: this.fragment,
|
fragment: this.fragment,
|
||||||
preserveQueryParams: attrBoolValue(this.preserveQueryParams),
|
preserveQueryParams: attrBoolValue(this.preserve),
|
||||||
|
queryParamsHandling: this.queryParamsHandling,
|
||||||
preserveFragment: attrBoolValue(this.preserveFragment),
|
preserveFragment: attrBoolValue(this.preserveFragment),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -140,12 +165,13 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
|
||||||
@HostBinding('attr.target') @Input() target: string;
|
@HostBinding('attr.target') @Input() target: string;
|
||||||
@Input() queryParams: {[k: string]: any};
|
@Input() queryParams: {[k: string]: any};
|
||||||
@Input() fragment: string;
|
@Input() fragment: string;
|
||||||
@Input() preserveQueryParams: boolean;
|
@Input() queryParamsHandling: QueryParamsHandling;
|
||||||
@Input() preserveFragment: boolean;
|
@Input() preserveFragment: boolean;
|
||||||
@Input() skipLocationChange: boolean;
|
@Input() skipLocationChange: boolean;
|
||||||
@Input() replaceUrl: boolean;
|
@Input() replaceUrl: boolean;
|
||||||
private commands: any[] = [];
|
private commands: any[] = [];
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
|
private preserve: boolean;
|
||||||
|
|
||||||
// the url displayed on the anchor element.
|
// the url displayed on the anchor element.
|
||||||
@HostBinding() href: string;
|
@HostBinding() href: string;
|
||||||
|
@ -169,6 +195,14 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set preserveQueryParams(value: boolean) {
|
||||||
|
if (isDevMode() && <any>console && <any>console.warn) {
|
||||||
|
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
|
||||||
|
}
|
||||||
|
this.preserve = value;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); }
|
ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); }
|
||||||
ngOnDestroy(): any { this.subscription.unsubscribe(); }
|
ngOnDestroy(): any { this.subscription.unsubscribe(); }
|
||||||
|
|
||||||
|
@ -199,7 +233,8 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
|
||||||
relativeTo: this.route,
|
relativeTo: this.route,
|
||||||
queryParams: this.queryParams,
|
queryParams: this.queryParams,
|
||||||
fragment: this.fragment,
|
fragment: this.fragment,
|
||||||
preserveQueryParams: attrBoolValue(this.preserveQueryParams),
|
preserveQueryParams: attrBoolValue(this.preserve),
|
||||||
|
queryParamsHandling: this.queryParamsHandling,
|
||||||
preserveFragment: attrBoolValue(this.preserveFragment),
|
preserveFragment: attrBoolValue(this.preserveFragment),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Location} from '@angular/common';
|
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 {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {Subject} from 'rxjs/Subject';
|
import {Subject} from 'rxjs/Subject';
|
||||||
|
@ -22,7 +22,7 @@ import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||||
import {reduce} from 'rxjs/operator/reduce';
|
import {reduce} from 'rxjs/operator/reduce';
|
||||||
|
|
||||||
import {applyRedirects} from './apply_redirects';
|
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 {createRouterState} from './create_router_state';
|
||||||
import {createUrlTree} from './create_url_tree';
|
import {createUrlTree} from './create_url_tree';
|
||||||
import {RouterOutlet} from './directives/router_outlet';
|
import {RouterOutlet} from './directives/router_outlet';
|
||||||
|
@ -102,12 +102,26 @@ export interface NavigationExtras {
|
||||||
/**
|
/**
|
||||||
* Preserves the query parameters for the next navigation.
|
* Preserves the query parameters for the next navigation.
|
||||||
*
|
*
|
||||||
|
* deprecated, use `queryParamsHandling` instead
|
||||||
|
*
|
||||||
* ```
|
* ```
|
||||||
* // Preserve query params from /results?page=1 to /view?page=1
|
* // Preserve query params from /results?page=1 to /view?page=1
|
||||||
* this.router.navigate(['/view'], { preserveQueryParams: true });
|
* this.router.navigate(['/view'], { preserveQueryParams: true });
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
preserveQueryParams?: boolean;
|
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
|
* Preserves the fragment for the next navigation
|
||||||
*
|
*
|
||||||
|
@ -465,11 +479,28 @@ export class Router {
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
createUrlTree(
|
createUrlTree(
|
||||||
commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams,
|
commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling,
|
||||||
preserveFragment}: NavigationExtras = {}): UrlTree {
|
preserveFragment}: NavigationExtras = {}): UrlTree {
|
||||||
|
if (isDevMode() && preserveQueryParams && <any>console && <any>console.warn) {
|
||||||
|
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
|
||||||
|
}
|
||||||
const a = relativeTo || this.routerState.root;
|
const a = relativeTo || this.routerState.root;
|
||||||
const q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams;
|
|
||||||
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
|
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);
|
return createUrlTree(a, this.currentUrlTree, commands, q, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1100,6 +1100,50 @@ describe('Integration', () => {
|
||||||
expect(native.getAttribute('href')).toEqual('/home?q=456#1');
|
expect(native.getAttribute('href')).toEqual('/home?q=456#1');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should correctly use the preserve strategy', fakeAsync(() => {
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'someRoot',
|
||||||
|
template:
|
||||||
|
`<router-outlet></router-outlet><a routerLink="/home" [queryParams]="{q: 456}" queryParamsHandling="preserve">Link</a>`
|
||||||
|
})
|
||||||
|
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:
|
||||||
|
`<router-outlet></router-outlet><a routerLink="/home" [queryParams]="{q: 456}" queryParamsHandling="merge">Link</a>`
|
||||||
|
})
|
||||||
|
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) => {
|
it('should support using links on non-a tags', fakeAsync(inject([Router], (router: Router) => {
|
||||||
const fixture = createRoot(router, RootCmp);
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
||||||
|
|
|
@ -127,8 +127,9 @@ export declare class NavigationError {
|
||||||
export interface NavigationExtras {
|
export interface NavigationExtras {
|
||||||
fragment?: string;
|
fragment?: string;
|
||||||
preserveFragment?: boolean;
|
preserveFragment?: boolean;
|
||||||
preserveQueryParams?: boolean;
|
/** @deprecated */ preserveQueryParams?: boolean;
|
||||||
queryParams?: Params;
|
queryParams?: Params;
|
||||||
|
queryParamsHandling?: QueryParamsHandling;
|
||||||
relativeTo?: ActivatedRoute;
|
relativeTo?: ActivatedRoute;
|
||||||
replaceUrl?: boolean;
|
replaceUrl?: boolean;
|
||||||
skipLocationChange?: boolean;
|
skipLocationChange?: boolean;
|
||||||
|
@ -209,7 +210,7 @@ export declare class Router {
|
||||||
url: string;
|
url: string;
|
||||||
urlHandlingStrategy: UrlHandlingStrategy;
|
urlHandlingStrategy: UrlHandlingStrategy;
|
||||||
constructor(rootComponentType: Type<any>, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes);
|
constructor(rootComponentType: Type<any>, 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;
|
dispose(): void;
|
||||||
initialNavigation(): void;
|
initialNavigation(): void;
|
||||||
isActive(url: string | UrlTree, exact: boolean): boolean;
|
isActive(url: string | UrlTree, exact: boolean): boolean;
|
||||||
|
@ -245,6 +246,7 @@ export declare class RouterLink {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
};
|
};
|
||||||
|
queryParamsHandling: QueryParamsHandling;
|
||||||
replaceUrl: boolean;
|
replaceUrl: boolean;
|
||||||
routerLink: any[] | string;
|
routerLink: any[] | string;
|
||||||
skipLocationChange: boolean;
|
skipLocationChange: boolean;
|
||||||
|
@ -277,6 +279,7 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
};
|
};
|
||||||
|
queryParamsHandling: QueryParamsHandling;
|
||||||
replaceUrl: boolean;
|
replaceUrl: boolean;
|
||||||
routerLink: any[] | string;
|
routerLink: any[] | string;
|
||||||
skipLocationChange: boolean;
|
skipLocationChange: boolean;
|
||||||
|
|
Loading…
Reference in New Issue