Angular: 配置默认QueryParamsHandling
Angular: configure default QueryParamsHandling
我构建了一个 angular 9 应用程序,并使用 @ngx-translate 添加了本地化。我已经配置了我的应用程序,以便它采用 lang
查询参数并相应地更改语言环境。
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute, private translateService: TranslateService) {
this.translateService.setDefaultLang('en');
this.route.queryParamMap.subscribe((params) => {
let lang = params.get('lang');
console.log('language', lang);
if (lang !== null) {
this.translateService.use(lang);
}
});
}
}
然后我在边栏上添加了 3 个按钮来更改查询参数(并切换语言)
<div class="p-1 text-center">
<a [routerLink]='[]' [queryParams]="{}">
<app-flag [country]="'en'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
<a [routerLink]='[]' [queryParams]="{'lang':'nl'}">
<app-flag [country]="'nl'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
<a [routerLink]='[]' [queryParams]="{'lang':'fr'}">
<app-flag [country]="'fr'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
</div>
这工作正常。但是当按下普通的 routerLink 时,或者在 router.navigate() 调用时,查询参数再次丢失。
我不想用 [queryParamsHandling]="'preserve'"
指令装饰我的应用程序中的每个 routerLink
,因为这是一项乏味的工作和可怕的做法。这个主题已经有一个 GitHub 问题,但是 angular 团队几乎没有处理它(已经 4 年了):https://github.com/angular/angular/issues/12664
有没有办法(任何方式)在导航时默认保留查询参数(或只是 lang
查询参数)?
我已经在默认 angular 路由器上创建了一个 ExtendedRouter
import { Router, QueryParamsHandling, NavigationExtras, UrlTree } from '@angular/router';
export class ExtendedRouter {
constructor(private router: Router) {
}
private _defaultQueryParamsHandling: QueryParamsHandling = null;
public get defaultQueryParamsHandling() {
return this._defaultQueryParamsHandling;
}
public set defaultQueryParamsHandling(value: QueryParamsHandling) {
this._defaultQueryParamsHandling = value;
}
public navigate(commands: any[], extras?: NavigationExtras) {
return this.router.navigate(commands, {
queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
fragment: extras.fragment,
preserveFragment: extras.preserveFragment,
queryParams: extras.queryParams,
relativeTo: extras.relativeTo,
replaceUrl: extras.replaceUrl,
skipLocationChange: extras.skipLocationChange
});
}
public navigateByUrl(url: string | UrlTree, extras?: NavigationExtras) {
return this.router.navigateByUrl(url, {
queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
fragment: extras.fragment,
preserveFragment: extras.preserveFragment,
queryParams: extras.queryParams,
relativeTo: extras.relativeTo,
replaceUrl: extras.replaceUrl,
skipLocationChange: extras.skipLocationChange
});
}
public createUrlTree(commands: any[], extras?: NavigationExtras) {
return this.router.createUrlTree(commands, extras);
}
public serializeUrl(url: UrlTree) {
return this.router.serializeUrl(url);
}
}
但这不涉及 [routerLink]
指令。我也试过创建一个,但我需要的所有字段都在 private
.
范围内
import { Directive, Renderer2, ElementRef, Attribute, Input } from '@angular/core';
import { RouterLink, Router, ActivatedRoute } from '@angular/router';
import { ExtendedRouter } from '../../helpers/extended-router';
@Directive({
selector: '[extendedRouterLink]'
})
export class ExtendedRouterLinkDirective extends RouterLink {
private router2: Router;
private route2: ActivatedRoute;
private commands2: any[] = [];
constructor(router: Router, route: ActivatedRoute, @Attribute('tabindex') tabIndex: string, renderer: Renderer2, el: ElementRef<any>, private extendedRouter: ExtendedRouter) {
super(router, route, tabIndex, renderer, el);
this.router2 = router;
this.route2 = route;
}
@Input()
set extendedRouterLink(commands: any[] | string | null | undefined) {
if (commands != null) {
this.commands2 = Array.isArray(commands) ? commands : [commands];
} else {
this.commands2 = [];
}
super.commands = commands;
}
get urlTree() {
return this.router2.createUrlTree(this.commands, {
relativeTo: this.route2,
queryParams: this.queryParams,
fragment: this.fragment,
queryParamsHandling: this.queryParamsHandling,
preserveFragment: this.attrBoolValue(this.preserveFragment),
});
}
private attrBoolValue = (s: any) => {
return s === '' || !!s;
}
}
有人知道如何解决这个问题而不必在每个 [routerLink]
上定义 [queryParamsHandling]
吗?
您可以将 router.navigate()
包装到一个实用程序 class 中,其方法将 router
本身以及您希望它执行的操作作为参数(可能使用可选的 parameters/default 值,或传递给它一个对象)并在默认情况下每次添加 queryParamsHandling
.
这种方法有一个小问题:
@Directive({
selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective extends RouterLinkWithHref {
queryParamsHandling: QueryParamsHandling = 'merge';
}
问题在于它扩展了 RouterLinkWithHref
,这意味着 <a routerLink="">
将附加 2 个指令(一个扩展另一个)。
和 this is what happens 在 RouterLinkWithHref
的 click
处理程序中:
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
state: this.state,
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
更重要的是它在发送到浏览器时的外观:
RouterLinkWithHref.prototype.onClick = function (button, ctrlKey, metaKey, shiftKey) {
if (button !== 0 || ctrlKey || metaKey || shiftKey) {
return true;
}
if (typeof this.target === 'string' && this.target != '_self') {
return true;
}
var extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
state: this.state
};
this.router.navigateByUrl(this.urlTree, extras);
return false;
};
这意味着当您单击 <a>
标记时,将调用 QueryParamsHandlingDirective.onClick
,然后是 RouterLinkWithHref.onClick
。但是由于最后调用 RouterLinkWithHref.onClick
,它不会将 queryParamsHandling
设置为 merge
。
解决方案是稍微修改自定义指令,使其不继承任何东西,而只是设置一个属性:
@Directive({
selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective {
constructor (routerLink: RouterLinkWithHref) {
routerLink.queryParamsHandling = 'merge';
}
}
最后我需要一种更灵活的方法,我可以保留一个查询参数 (lang) 但删除另一个 (return-url)。所以最终我决定继续写我自己的 AdvancedRouter
和 advRouterLink
.
可让您设置配置的提供商:
import { InjectionToken } from "@angular/core";
import { QueryParamsConfig } from "../../interfaces/query-params-config";
export const QUERY_PARAMS_CONFIG = new InjectionToken<QueryParamsConfig>('QueryParamsConfig');
提供者值的接口:
import { QueryParamsHandling } from "@angular/router";
export interface QueryParamsConfig {
[key: string]: QueryParamsHandling;
}
在 AppModule
中配置此提供程序:
@NgModule({
declarations: [
AppComponent
],
imports: [
...
AdvancedRouterModule
],
providers: [{
provide: QUERY_PARAMS_CONFIG, useValue: <QueryParamsConfig>{
'lang': 'preserve',
'return': ''
}
}],
bootstrap: [AppComponent]
})
export class AppModule { }
AdvancedRouter
import { Inject, Injectable } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { ActivatedRoute, NavigationBehaviorOptions, NavigationExtras, Params, Router, UrlCreationOptions, UrlTree } from '@angular/router';
import { QueryParamsConfig } from '../../interfaces/query-params-config';
import { QUERY_PARAMS_CONFIG } from '../../providers';
import { UrlWithQueryParams } from './url-with-query-params';
@Injectable({
providedIn: 'root'
})
export class AdvancedRouter {
constructor(private router: Router, private route: ActivatedRoute, @Inject(QUERY_PARAMS_CONFIG) private queryParamsConfig: QueryParamsConfig) {
}
public navigate(commands: any[], extras?: NavigationExtras) {
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, extras?.queryParams);
return this.router.navigate(commands, { ...extras, queryParams: newParams });
}
public navigateByUrl(url: string | UrlTree, extras?: NavigationBehaviorOptions) {
// The requested url.
let urlValue = url instanceof UrlTree
? this.router.serializeUrl(url)
: url;
// The requested query parameters.
const requestedParams = this.extractQueryParametersFromUrl(urlValue);
// Use the current queryparams and requested queryparams
// to compute the new parameters according to the configuration.
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, requestedParams.queryParams);
const newParamKeys = Object.keys(newParams).filter(key => !['encoder', 'map'].includes(key));
const newQueryString = newParamKeys.map(key => `${key}=${newParams[key]}`).join('&');
const newUrl = newParamKeys.length === 0
? requestedParams.url
: `${requestedParams.url}?${newQueryString}`;
return this.router.navigateByUrl(newUrl, extras);
}
public createUrlTree(commands: any[], extras?: UrlCreationOptions) {
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, extras?.queryParams);
return this.router.createUrlTree(commands, { ...extras, queryParams: newParams });
}
public serializeUrl(url: UrlTree) {
return this.router.serializeUrl(url);
}
private extractQueryParametersFromUrl(url: string) : UrlWithQueryParams {
if (url.includes('?')) {
const parts = url.split('?');
return {
url: parts[0],
queryParams: new HttpParams({ fromString: parts[1] })
};
} else {
return {
url: url,
queryParams: new HttpParams()
};
}
}
private containsKey(params: Params, key: string) {
return Object.keys(params).indexOf(key) > -1;
}
private computeQueryParameters(currentParams: Params, requestedParams: Params | null | undefined) {
// Allow a null object to be passed to this method.
const newRequestedParams = requestedParams ?? { };
// Merge the set of keys.
const allParamKeys = Object.keys({
...currentParams,
...newRequestedParams
});
return <Params>Object.assign({}, ...allParamKeys.map(k => {
// Compute new value for each Query parameter.
return {
key: k,
value: this.getQueryParameterValue(currentParams, newRequestedParams, k)
};
})
// Remove query parameters to drop.
.filter(p => p.value !== null)
// ToDictionary
.map(p => {
return { [p.key] : p.value };
})
);
}
private getQueryParameterValue(currentParams: Params, requestedParams: Params, key: string) {
switch (this.queryParamsConfig[key]) {
case 'preserve':
// Take requested value if present, else take current.
// Must use containsKey since one may want to explicitly pass a null value for a specific parameter,
// in order to drop the query parameter specified.
return Object.keys(requestedParams).indexOf(key) === -1
? currentParams[key]
: requestedParams[key];
case 'merge':
if (this.containsKey(currentParams, key)) {
if (this.containsKey(requestedParams, key)) {
// Query parameter present in both. Merge both values.
return `${currentParams[key]},${requestedParams[key]}`;
} else {
// Query parameter only present in activated route.
return currentParams[key];
}
} else {
if (this.containsKey(requestedParams, key)) {
// Query parameter only present in requested list.
return requestedParams[key];
} else {
// Never occurs
}
}
break;
default:
// Default is drop query parameter.
if (this.containsKey(requestedParams, key)) {
// If still present in requested list, return this value.
return requestedParams[key];
} else {
// Drop query parameter.
return null;
}
}
}
}
UrlWithQueryParams
import { Params } from "@angular/router";
export interface UrlWithQueryParams {
url: string;
queryParams: Params;
}
AdvancedRouterLinkDirective
import { LocationStrategy } from '@angular/common';
import { Directive, Input } from '@angular/core';
import { ActivatedRoute, Router, RouterLinkWithHref, UrlTree } from '@angular/router';
import { AdvancedRouter } from '../../services/advanced-router/advanced-router';
// See https://github.com/angular/angular/blob/master/packages/router/src/directives/router_link.ts#L256
@Directive({selector: 'a[advRouterLink],area[advRouterLink]'})
export class AdvancedRouterLinkDirective extends RouterLinkWithHref {
constructor(
private advancedRouter: AdvancedRouter,
private nativeRoute: ActivatedRoute,
nativeRouter: Router,
nativeLocationStrategy: LocationStrategy
) {
super(nativeRouter, nativeRoute, nativeLocationStrategy);
}
private nativeCommands: any[] = [];
@Input()
set advRouterLink(commands: any[] | string | null | undefined) {
if (commands != null) {
this.nativeCommands = Array.isArray(commands) ? commands : [commands];
} else {
this.nativeCommands = [];
}
}
get urlTree(): UrlTree {
return this.advancedRouter.createUrlTree(this.nativeCommands, {
relativeTo: this.relativeTo !== undefined ? this.relativeTo : this.nativeRoute,
queryParams: this.queryParams,
fragment: this.fragment,
queryParamsHandling: '', // Drop queryparams and let the AdvancedRouter do all the work
preserveFragment: this.attrBoolValue(this.preserveFragment),
});
}
private attrBoolValue(s: any) {
return s === '' || !!s;
}
}
我构建了一个 angular 9 应用程序,并使用 @ngx-translate 添加了本地化。我已经配置了我的应用程序,以便它采用 lang
查询参数并相应地更改语言环境。
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute, private translateService: TranslateService) {
this.translateService.setDefaultLang('en');
this.route.queryParamMap.subscribe((params) => {
let lang = params.get('lang');
console.log('language', lang);
if (lang !== null) {
this.translateService.use(lang);
}
});
}
}
然后我在边栏上添加了 3 个按钮来更改查询参数(并切换语言)
<div class="p-1 text-center">
<a [routerLink]='[]' [queryParams]="{}">
<app-flag [country]="'en'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
<a [routerLink]='[]' [queryParams]="{'lang':'nl'}">
<app-flag [country]="'nl'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
<a [routerLink]='[]' [queryParams]="{'lang':'fr'}">
<app-flag [country]="'fr'" [appHoverClass]="'brightness-250'"></app-flag>
</a>
</div>
这工作正常。但是当按下普通的 routerLink 时,或者在 router.navigate() 调用时,查询参数再次丢失。
我不想用 [queryParamsHandling]="'preserve'"
指令装饰我的应用程序中的每个 routerLink
,因为这是一项乏味的工作和可怕的做法。这个主题已经有一个 GitHub 问题,但是 angular 团队几乎没有处理它(已经 4 年了):https://github.com/angular/angular/issues/12664
有没有办法(任何方式)在导航时默认保留查询参数(或只是 lang
查询参数)?
我已经在默认 angular 路由器上创建了一个 ExtendedRouter
import { Router, QueryParamsHandling, NavigationExtras, UrlTree } from '@angular/router';
export class ExtendedRouter {
constructor(private router: Router) {
}
private _defaultQueryParamsHandling: QueryParamsHandling = null;
public get defaultQueryParamsHandling() {
return this._defaultQueryParamsHandling;
}
public set defaultQueryParamsHandling(value: QueryParamsHandling) {
this._defaultQueryParamsHandling = value;
}
public navigate(commands: any[], extras?: NavigationExtras) {
return this.router.navigate(commands, {
queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
fragment: extras.fragment,
preserveFragment: extras.preserveFragment,
queryParams: extras.queryParams,
relativeTo: extras.relativeTo,
replaceUrl: extras.replaceUrl,
skipLocationChange: extras.skipLocationChange
});
}
public navigateByUrl(url: string | UrlTree, extras?: NavigationExtras) {
return this.router.navigateByUrl(url, {
queryParamsHandling: extras.queryParamsHandling ?? this.defaultQueryParamsHandling ?? '',
fragment: extras.fragment,
preserveFragment: extras.preserveFragment,
queryParams: extras.queryParams,
relativeTo: extras.relativeTo,
replaceUrl: extras.replaceUrl,
skipLocationChange: extras.skipLocationChange
});
}
public createUrlTree(commands: any[], extras?: NavigationExtras) {
return this.router.createUrlTree(commands, extras);
}
public serializeUrl(url: UrlTree) {
return this.router.serializeUrl(url);
}
}
但这不涉及 [routerLink]
指令。我也试过创建一个,但我需要的所有字段都在 private
.
import { Directive, Renderer2, ElementRef, Attribute, Input } from '@angular/core';
import { RouterLink, Router, ActivatedRoute } from '@angular/router';
import { ExtendedRouter } from '../../helpers/extended-router';
@Directive({
selector: '[extendedRouterLink]'
})
export class ExtendedRouterLinkDirective extends RouterLink {
private router2: Router;
private route2: ActivatedRoute;
private commands2: any[] = [];
constructor(router: Router, route: ActivatedRoute, @Attribute('tabindex') tabIndex: string, renderer: Renderer2, el: ElementRef<any>, private extendedRouter: ExtendedRouter) {
super(router, route, tabIndex, renderer, el);
this.router2 = router;
this.route2 = route;
}
@Input()
set extendedRouterLink(commands: any[] | string | null | undefined) {
if (commands != null) {
this.commands2 = Array.isArray(commands) ? commands : [commands];
} else {
this.commands2 = [];
}
super.commands = commands;
}
get urlTree() {
return this.router2.createUrlTree(this.commands, {
relativeTo: this.route2,
queryParams: this.queryParams,
fragment: this.fragment,
queryParamsHandling: this.queryParamsHandling,
preserveFragment: this.attrBoolValue(this.preserveFragment),
});
}
private attrBoolValue = (s: any) => {
return s === '' || !!s;
}
}
有人知道如何解决这个问题而不必在每个 [routerLink]
上定义 [queryParamsHandling]
吗?
您可以将 router.navigate()
包装到一个实用程序 class 中,其方法将 router
本身以及您希望它执行的操作作为参数(可能使用可选的 parameters/default 值,或传递给它一个对象)并在默认情况下每次添加 queryParamsHandling
.
这种方法有一个小问题:
@Directive({
selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective extends RouterLinkWithHref {
queryParamsHandling: QueryParamsHandling = 'merge';
}
问题在于它扩展了 RouterLinkWithHref
,这意味着 <a routerLink="">
将附加 2 个指令(一个扩展另一个)。
和 this is what happens 在 RouterLinkWithHref
的 click
处理程序中:
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
state: this.state,
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
更重要的是它在发送到浏览器时的外观:
RouterLinkWithHref.prototype.onClick = function (button, ctrlKey, metaKey, shiftKey) {
if (button !== 0 || ctrlKey || metaKey || shiftKey) {
return true;
}
if (typeof this.target === 'string' && this.target != '_self') {
return true;
}
var extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
state: this.state
};
this.router.navigateByUrl(this.urlTree, extras);
return false;
};
这意味着当您单击 <a>
标记时,将调用 QueryParamsHandlingDirective.onClick
,然后是 RouterLinkWithHref.onClick
。但是由于最后调用 RouterLinkWithHref.onClick
,它不会将 queryParamsHandling
设置为 merge
。
解决方案是稍微修改自定义指令,使其不继承任何东西,而只是设置一个属性:
@Directive({
selector: 'a[routerLink]'
})
export class QueryParamsHandlingDirective {
constructor (routerLink: RouterLinkWithHref) {
routerLink.queryParamsHandling = 'merge';
}
}
最后我需要一种更灵活的方法,我可以保留一个查询参数 (lang) 但删除另一个 (return-url)。所以最终我决定继续写我自己的 AdvancedRouter
和 advRouterLink
.
可让您设置配置的提供商:
import { InjectionToken } from "@angular/core";
import { QueryParamsConfig } from "../../interfaces/query-params-config";
export const QUERY_PARAMS_CONFIG = new InjectionToken<QueryParamsConfig>('QueryParamsConfig');
提供者值的接口:
import { QueryParamsHandling } from "@angular/router";
export interface QueryParamsConfig {
[key: string]: QueryParamsHandling;
}
在 AppModule
中配置此提供程序:
@NgModule({
declarations: [
AppComponent
],
imports: [
...
AdvancedRouterModule
],
providers: [{
provide: QUERY_PARAMS_CONFIG, useValue: <QueryParamsConfig>{
'lang': 'preserve',
'return': ''
}
}],
bootstrap: [AppComponent]
})
export class AppModule { }
AdvancedRouter
import { Inject, Injectable } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { ActivatedRoute, NavigationBehaviorOptions, NavigationExtras, Params, Router, UrlCreationOptions, UrlTree } from '@angular/router';
import { QueryParamsConfig } from '../../interfaces/query-params-config';
import { QUERY_PARAMS_CONFIG } from '../../providers';
import { UrlWithQueryParams } from './url-with-query-params';
@Injectable({
providedIn: 'root'
})
export class AdvancedRouter {
constructor(private router: Router, private route: ActivatedRoute, @Inject(QUERY_PARAMS_CONFIG) private queryParamsConfig: QueryParamsConfig) {
}
public navigate(commands: any[], extras?: NavigationExtras) {
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, extras?.queryParams);
return this.router.navigate(commands, { ...extras, queryParams: newParams });
}
public navigateByUrl(url: string | UrlTree, extras?: NavigationBehaviorOptions) {
// The requested url.
let urlValue = url instanceof UrlTree
? this.router.serializeUrl(url)
: url;
// The requested query parameters.
const requestedParams = this.extractQueryParametersFromUrl(urlValue);
// Use the current queryparams and requested queryparams
// to compute the new parameters according to the configuration.
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, requestedParams.queryParams);
const newParamKeys = Object.keys(newParams).filter(key => !['encoder', 'map'].includes(key));
const newQueryString = newParamKeys.map(key => `${key}=${newParams[key]}`).join('&');
const newUrl = newParamKeys.length === 0
? requestedParams.url
: `${requestedParams.url}?${newQueryString}`;
return this.router.navigateByUrl(newUrl, extras);
}
public createUrlTree(commands: any[], extras?: UrlCreationOptions) {
const newParams = this.computeQueryParameters(this.route.snapshot.queryParams, extras?.queryParams);
return this.router.createUrlTree(commands, { ...extras, queryParams: newParams });
}
public serializeUrl(url: UrlTree) {
return this.router.serializeUrl(url);
}
private extractQueryParametersFromUrl(url: string) : UrlWithQueryParams {
if (url.includes('?')) {
const parts = url.split('?');
return {
url: parts[0],
queryParams: new HttpParams({ fromString: parts[1] })
};
} else {
return {
url: url,
queryParams: new HttpParams()
};
}
}
private containsKey(params: Params, key: string) {
return Object.keys(params).indexOf(key) > -1;
}
private computeQueryParameters(currentParams: Params, requestedParams: Params | null | undefined) {
// Allow a null object to be passed to this method.
const newRequestedParams = requestedParams ?? { };
// Merge the set of keys.
const allParamKeys = Object.keys({
...currentParams,
...newRequestedParams
});
return <Params>Object.assign({}, ...allParamKeys.map(k => {
// Compute new value for each Query parameter.
return {
key: k,
value: this.getQueryParameterValue(currentParams, newRequestedParams, k)
};
})
// Remove query parameters to drop.
.filter(p => p.value !== null)
// ToDictionary
.map(p => {
return { [p.key] : p.value };
})
);
}
private getQueryParameterValue(currentParams: Params, requestedParams: Params, key: string) {
switch (this.queryParamsConfig[key]) {
case 'preserve':
// Take requested value if present, else take current.
// Must use containsKey since one may want to explicitly pass a null value for a specific parameter,
// in order to drop the query parameter specified.
return Object.keys(requestedParams).indexOf(key) === -1
? currentParams[key]
: requestedParams[key];
case 'merge':
if (this.containsKey(currentParams, key)) {
if (this.containsKey(requestedParams, key)) {
// Query parameter present in both. Merge both values.
return `${currentParams[key]},${requestedParams[key]}`;
} else {
// Query parameter only present in activated route.
return currentParams[key];
}
} else {
if (this.containsKey(requestedParams, key)) {
// Query parameter only present in requested list.
return requestedParams[key];
} else {
// Never occurs
}
}
break;
default:
// Default is drop query parameter.
if (this.containsKey(requestedParams, key)) {
// If still present in requested list, return this value.
return requestedParams[key];
} else {
// Drop query parameter.
return null;
}
}
}
}
UrlWithQueryParams
import { Params } from "@angular/router";
export interface UrlWithQueryParams {
url: string;
queryParams: Params;
}
AdvancedRouterLinkDirective
import { LocationStrategy } from '@angular/common';
import { Directive, Input } from '@angular/core';
import { ActivatedRoute, Router, RouterLinkWithHref, UrlTree } from '@angular/router';
import { AdvancedRouter } from '../../services/advanced-router/advanced-router';
// See https://github.com/angular/angular/blob/master/packages/router/src/directives/router_link.ts#L256
@Directive({selector: 'a[advRouterLink],area[advRouterLink]'})
export class AdvancedRouterLinkDirective extends RouterLinkWithHref {
constructor(
private advancedRouter: AdvancedRouter,
private nativeRoute: ActivatedRoute,
nativeRouter: Router,
nativeLocationStrategy: LocationStrategy
) {
super(nativeRouter, nativeRoute, nativeLocationStrategy);
}
private nativeCommands: any[] = [];
@Input()
set advRouterLink(commands: any[] | string | null | undefined) {
if (commands != null) {
this.nativeCommands = Array.isArray(commands) ? commands : [commands];
} else {
this.nativeCommands = [];
}
}
get urlTree(): UrlTree {
return this.advancedRouter.createUrlTree(this.nativeCommands, {
relativeTo: this.relativeTo !== undefined ? this.relativeTo : this.nativeRoute,
queryParams: this.queryParams,
fragment: this.fragment,
queryParamsHandling: '', // Drop queryparams and let the AdvancedRouter do all the work
preserveFragment: this.attrBoolValue(this.preserveFragment),
});
}
private attrBoolValue(s: any) {
return s === '' || !!s;
}
}