Je vais avoir une application angulaire 2 avec plusieurs enfants imbriqués voir. Mais il sera affiché sur la même page si plusieurs router-outlet
.
const routes: Routes = [
{
path: 'queue/:date/:offset/:type',
component: BundleListComponent,
resolve: {
response: BundleListResolve
},
children: [
{
path: ':bundleId', component: PointListComponent,
resolve: {
response: PointListResolve
},
children: [
{
path: ':pointId', component: TaskListComponent,
resolve: {
response: TaskListResolve
},
children: [
{
path: ':taskId', component: TaskDetailComponent,
resolve: {
response: TaskDetailResolve
}
},
{ path: '', component: EmptyComponent }
]
},
{ path: '', component: EmptyComponent }
]
},
{ path: '', component: EmptyComponent }
]
},
{
path: 'queue',
component: QueueRedirectComponent
}
}
Donc, fondamentalement, je peux parcourir la liste des itinéraires
Par exemple
#/queue/2017-01-05/480/20/57f4c26507b36e3684007b52/1/57fb0abb07b36e39d8e88df8/1
Imaginez que vous avez une page avec un élément:
En gros, je peux toujours cliquer sur la liste de films pendant que je regarde un détail de personnage.
Si vous cherchez à définir le nom de chaque itinéraire mais que tout semble indiquer le résultat, cette fonctionnalité a déjà été supprimée de Angular 2 final. Dans Angular 1, à l’aide du routeur UI, je peux définir le nom de chaque itinéraire et l’obtenir très facilement avec la fonction intégrée state.is(ROUTE_NAME)
.
Donc ce que je fais maintenant est basé sur le window.location pour obtenir l'URL et le fractionnement de cette chaîne par /
pour obtenir le nombre de paramètres. Mais c'est plus codé en dur.
Une expérience sur faire la même chose? Comment puis-je distinguer quel itinéraire est actuellement actif?
Je pense qu'il y a un problème avec la réponse de Scott qui utilise ActivatedRoute dans le constructeur du service. Cet itinéraire ne sera pas mis à jour.
J'ai pensé à une autre solution qui pourrait intéresser votre intérêt. Cela revient encore à utiliser la propriété data
sur les routes, mais maintenant à l'aide d'un autre service de résolution:
Vous allez avoir besoin d'une RouterConfig
comme celle-ci, où pour chaque route vous ajoutez le state: StateResolve
et un objet de données contenant le nom de l'état:
const routes: RouterConfig = [{
path: 'queue/:date/:offset/:type',
component: BundleListComponent,
resolve: {
response: BundleListResolve,
state: StateResolve
},
data: {
state: 'Bundle'
},
...
]
N'oubliez pas d'ajouter le service StateResolve au groupe de fournisseurs
Votre service StateResolve
ressemblera à ceci:
@Injectable()
export class StateResolve implements Resolve<string> {
constructor(private stateService: StateService) {}
resolve(route: ActivatedRouteSnapshot): string {
let state: string = route.data['state']
this.stateService.setState(state);
return state;
}
}
De toute évidence, vous aurez besoin d'une StateService
qui utilise la méthode setState
, mais à partir de là, c'est assez explicite.
Utiliser une garde resolve
est peut-être un peu excentrique, mais si vous y réfléchissez, vous essayez de résoudre les données avant de montrer la route. Dans ce cas, l'état à l'intérieur de la variable data, il est donc logique d'utiliser la variable Resolve
pour accéder à la propriété data
.
Créez un service appelé ActiveState
qui subscribe
permettra de modifier le routeur, à l'aide de router.events.subscribe
:
import {Injectable} from "@angular/core";
import {Router, ActivatedRoute, NavigationEnd} from "@angular/router";
@Injectable()
export class ActiveState {
public name : string;
constructor(router : Router, route : ActivatedRoute)
{
router.events.subscribe(event => {
if(event instanceof NavigationEnd){
// Traverse the active route tree
var snapshot = route.snapshot;
var activated = route.firstChild;
if(activated != null) {
while (activated != null) {
snapshot = activated.snapshot;
activated = activated.firstChild;
}
}
// Try finding the 'stateName' from the data
this.name = snapshot.data['stateName'] || "unnamed";
}
});
}
is(name : string) : boolean
{
return this.name === name;
}
}
Ensuite, sur votre route, nous ajoutons une valeur simple au paramètre data
de la route appelée stateName
pour chaque état que nous voulons nommer:
const routes: Routes = [
{
path: 'queue/:date/:offset/:type',
component: BundleListComponent,
resolve: { response: BundleListResolve }
data: { stateName: 'Bundle' },
children: [
{
path: ':bundleId', component: PointListComponent,
resolve: { response: PointListResolve },
data: { stateName: 'Point'}
}
...
Ensuite, lorsque vous injectez state : ActiveState
, vous pouvez simplement tester la valeur state.is("Point")
Créez un service appelé ActiveState
:
import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
@Injectable()
export class ActiveState {
public current : Observable<string>;
private observer : any;
constructor()
{
// Create an observable (it can be subscribed to)
this.current = new Observable(observer => {
this.observer = observer;
observer.next('Unknown'); // The default unknown state
});
}
setActive(name : string) : void
{
this.observer.next(name);
}
}
Dans vos résolveurs tels que PointListResolve
... TaskListResolve
etc.
import {Resolve, ActivatedRouteSnapshot} from "@angular/router";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
import {ActiveState} from "services/ActiveState.service";
@Injectable()
export class PointListResolver implements Resolve<any> {
// Inject the ActiveState in your constructor
constructor(private state : ActiveState) {}
resolve(route: ActivatedRouteSnapshot): Observable<any> {
// Set the active state name
this.state.setActive("Point"); // We are here: /queue/:date/:offset/:type/:bundleId/:pointId
// Do your regular resolve functionality (if you don't need to resolve, this blank resolver of an empty object will work)
// ...
return Observable.of({});
}
}
Ainsi, dans les autres résolveurs, mettez à jour la valeur this.state.setActive("")
comme requis.
Ensuite, pour déterminer l’état dans lequel vous vous trouvez, injectez ActiveState
à l’emplacement où vous souhaitez utiliser l’état actuel, par exemple dans un @Component
, c.-à-d.
import {Component, OnDestroy} from '@angular/core';
import {ActiveState} from "services/ActiveState.service";
@Component({
selector: 'my-current-state-component',
template: `The current state is: {{stateName}}`,
})
export class MyCurrentStateComponent implements OnDestroy {
public stateName : string;
private sub : Subscription;
// Inject in ActiveState
constructor(private state : ActiveState)
{
// Subscribe to the current State
this.sub = state.current.subscribe(name => {
this.stateName = name;
// Other logic to perform when the active route name changes
...
});
}
ngOnDestroy()
{
this.sub.unsubscribe();
}
}
Remarques:
N'oubliez pas d'enregistrer votre service ActiveState
en tant que Provider
dans:
@NgModule({
...
providers:[ActiveState]
...
})
export class AppModule { }
Plus simple - Version non observable J'ai utilisé un Observable<string>
afin que les modifications apportées à l'état actif puissent prendre la valeur subscribed
, mais ceci pourrait être simplifié pour devenir simplement une string
si vous ne voulez pas cette fonctionnalité:
import {Injectable} from "@angular/core";
@Injectable()
export class ActiveState {
public current : string;
setActive(name : string) : void
{
this.current = name;
}
is(name : string) : boolean
{
return name == this.current;
}
}
Ensuite, lorsque vous injectez state : ActiveState
, vous pouvez simplement tester la valeur state.is("Point")
J'espère que c'est utile.
name
a été retiré des routes il y a longtemps, mais les routes permettent d'ajouter des données arbitraires
const routes: RouterConfig = [
{
path: '',
redirectTo: '/login',
pathMatch: 'full',
},
{
path: 'login',
component: LoginComponent,
data: {title: 'Login'}
},
{
path: 'home',
component: HomeComponent,
data: {title: 'Home'}
},
{
path: 'wepays',
component: WePaysComponent,
data: {title: 'WePays'}
}
];
Ce code construit un titre à partir des noms de tous les segments de route. Cela pourrait probablement être simplifié pour votre cas d'utilisation.
export class AppComponent {
constructor(titleService:Title, router:Router, activatedRoute:ActivatedRoute) {
router.events.subscribe(event => {
if(event instanceof NavigationEnd) {
var title = this.getTitle(router.routerState, router.routerState.root).join('-');
console.log('title', title);
titleService.setTitle(title);
}
});
}
// collect that title data properties from all child routes
// there might be a better way but this worked for me
getTitle(state, parent) {
var data = [];
if(parent && parent.snapshot.data && parent.snapshot.data.title) {
data.Push(parent.snapshot.data.title);
}
if(state && parent) {
data.Push(... this.getTitle(state, state.firstChild(parent)));
}
return data;
}
}
Voir aussi Changement du titre de la page à l’aide du nouveau routeur Angular 2
ma réponse est similaire, mais l'a fait d'une manière différente, donc je pense qu'il est bon de poster
Ce qui est différent: je n'ai pas besoin de changer quoi que ce soit sur mes routes, j'ai créé un service pour suivre ActivatedRoute plus en profondeur (inside ou firstChild ... firstChild).
créer le service
import { Injectable } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
@Injectable()
export class ActivatedRouteService {
private _deeperActivatedRoute: ActivatedRoute;
get deeperActivatedRoute(): ActivatedRoute {
return this._deeperActivatedRoute;
}
constructor(private router: Router, private route: ActivatedRoute) {}
init(): void {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
// Traverse the active route tree
let activatedChild = this.route.firstChild;
if (activatedChild != null) {
let nextActivatedChild;
while (nextActivatedChild != null) {
nextActivatedChild = activatedChild.firstChild;
if (nextActivatedChild != null) {
activatedChild = activatedChild.firstChild;
}
}
}
this._deeperActivatedRoute = activatedChild || this.route;
}
});
}
}
puis dans app.component.ts je lance le service (juste pour m'assurer qu'il est toujours suivi)
export class AppComponent {
constructor(private activatedRouteService: ActivatedRouteService) {
this.activatedRouteService.init();
}
}
et enfin, prenez votre itinéraire où que vous soyez, comme service:
export class ForbiddenInterceptor implements HttpInterceptor {
constructor(private activatedRouteService: ActivatedRouteService) { }
doYourStuff(): void {
//you'll have the correct activatedRoute here
this.activatedRouteService.deeperActivatedRoute;
}
}
pour répondre à la question, vous pouvez simplement prendre deeperActivatedRoute et vérifier normalement le fichier snapshop.url, comme vous le feriez dans un composant.