Étant donné une configuration de route
{
path: '/root/:rootId',
children: [{
path: '/child1/:child1Id',
children: [{
path: '/child2/:child2Id
component: TestComponent
}]
}]
}
Dans TestComponent, comment puis-je obtenir facilement tous les paramètres de route. Je me demande s’il existe un moyen plus facile que
let rootId = route.parent.parent.snapshot.params;
let child1Id = route.parent.snapshot.params;
let child2Id = route.snapshot.params;
Cela semble excessivement redondant, surtout si je regarde les paramètres de route observables au lieu d’y accéder par le biais de la capture instantanée de route. Cette méthode semble également fragile, car elle casserait si je déplaçais n’importe laquelle des routes/paramètres. Je suis habitué au routeur ui angulaire où un seul objet $ stateParams était fourni avec toutes les données param facilement accessibles. J'ai les mêmes préoccupations concernant les données résolues par la route et l'accès à partir d'un seul nœud dans l'arbre de la route. Toute aide serait très appréciée. Merci d'avance
À partir de Angular 5.2, vous pouvez configurer le routeur pour hériter de tous les paramètres en tant qu'enfants. Voir cet engagement si vous êtes intéressé par les détails sanglants, mais voici comment cela fonctionne pour moi:
Où que vous appeliez RouterModule.forRoot()
, incluez un objet de configuration avec la stratégie d'héritage définie sur always
(la valeur par défaut est emptyOnly
):
import {RouterModule, ExtraOptions} from "@angular/router";
export const routingConfiguration: ExtraOptions = {
paramsInheritanceStrategy: 'always'
};
export const Routing = RouterModule.forRoot(routes, routingConfiguration);
Désormais, lorsque vous êtes dans un composant enfant qui regarde une ActivatedRoute
, les paramètres des ancêtres y apparaissent (par exemple, activatedRoute.params
) plutôt que quelque chose de compliqué comme activatedRoute.parent.parent.parent.params
. Vous pouvez accéder à la valeur directement (par exemple, activatedRoute.params.value.userId
) ou vous abonner via activatedRoute.params.subscribe(...)
.
Vous devez itérer les segments de route.
Quelque chose comme
var params = [];
var route = router.routerState.snapshot.root;
do {
params.Push(route.params);
route = route.firstChild;
} while(route);
Cela vous donne la liste de params
de chaque segment de route, vous pouvez alors lire les valeurs param qui vous intéressent.
Object.keys(params)
pourrait fonctionner pour obtenir tous les noms de paramètres disponibles à partir d'une instance param
.
J'ai créé le service suivant pour pouvoir obtenir tous les paramètres de route en tant que ParamMap . L’idée principale est d’analyser récursivement tous les paramètres des routes enfants.
import {Injectable} from '@angular/core';
import {
ActivatedRoute,
Router,
NavigationEnd,
ParamMap,
PRIMARY_OUTLET,
RouterEvent
} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
@Injectable()
export class ParamMapService {
paramMap: Observable<ParamMap>;
constructor(private router: Router,
private route: ActivatedRoute) {
this.paramMap = this.getParamMapObservable();
}
private getParamMap(route: ActivatedRoute): ParamMap {
const map: Map<string, string | string[]> = new Map();
while (route) {
route.snapshot.paramMap.keys.forEach((key) => {
map.set(key, this.getParamMapValue(route.snapshot.paramMap, key));
});
route = route.firstChild;
}
return <ParamMap>{
keys: this.getParamMapKeys(map),
has: this.getParamMapMethodHas(map),
get: this.getParamMapMethodGet(map),
getAll: this.getParamMapMethodGetAll(map)
};
}
private getParamMapMethodGet(map: Map<string, string | string[]>): (name: string) => string | null {
return (name: string): string | null => {
const value = map.get(name);
if (typeof value === 'string') {
return value;
}
if (Array.isArray(value) && value.length) {
return value[0];
}
return null;
};
}
private getParamMapMethodGetAll(map: Map<string, string | string[]>): (name: string) => string[] {
return (name: string): string[] => {
const value = map.get(name);
if (typeof value === 'string') {
return [value];
}
if (Array.isArray(value)) {
return value;
}
return [];
};
}
private getParamMapMethodHas(map: Map<string, string | string[]>): (name: string) => boolean {
return (name: string): boolean => map.has(name);
}
private getParamMapKeys(map: Map<string, string | string[]>): string[] {
return Array.from(map.keys());
}
private getParamMapObservable(): Observable<ParamMap> {
return this.router.events
.filter((event: RouterEvent) => event instanceof NavigationEnd)
.map(() => this.route)
.filter((route: ActivatedRoute) => route.outlet === PRIMARY_OUTLET)
.map((route: ActivatedRoute) => this.getParamMap(route));
}
private getParamMapValue(paramMap: ParamMap, key: string): string | string[] {
return (paramMap.getAll(key).length > 1 ? paramMap.getAll(key) : paramMap.get(key));
}
}
Exemple d'utilisation
id;
constructor(private paramMapService: ParamMapService) {
this.paramMapService.paramMap.subscribe(paramMap => {
this.id = paramMap.get('id');
});
}
Remarque
ES6 Map est utilisé dans le service. Pour prendre en charge les anciens navigateurs, effectuez l’une des opérations suivantes:
import 'core-js/es6/map';
dans polyfills.ts
, ouconstructor(private route: ActivatedRoute) {}
data$ = of(this.route).pipe(
expand(route => of(route['parent'])),
takeWhile(route => !!route['parent']),
pluck('snapshot', 'data'),
reduce(merge));
Explication:
L'appel expand ici crée un observable pour chaque itinéraire de la chaîne parente. Takewhile est utilisé pour qu'il arrête de se répéter lorsque route ['parent'] renvoie la valeur null ou sur la route racine.
Ensuite, pour toutes les routes de l'observable, Pluck mappera chacune d'elles sur sa propriété 'snapshot.data'.
Enfin, réduire est alimenté la fonction de fusion de lodash pour combiner tous les objets de données en un seul objet. Ce flux regroupe toutes les données de la route en cours via les routes parentes
Angulaire 5:
import { combineLatest } from 'rxjs/observable/combineLatest';
constructor(
private activatedRoute: ActivatedRoute
) {
combineLatest(
this.activatedRoute.data,
this.activatedRoute.params
).subscribe(([{from}, params]) => {
this.params.from = from;
this.params.id = params['id'];
this.loadData();
});
}