web-dev-qa-db-fra.com

Angular 2 new Router: Comment obtenir les paramètres de routeur d’un composant enfant?

Dans la dernière version de @angular/router3.0.0-rc.1 La façon dont vous obtenez les paramètres depuis une URL/une route a été modifiée.

Basé sur this documentation, vous devriez pouvoir obtenir les paramètres en vous abonnant, mais dans mon cas, il semble que cela ne fonctionne pas.

Ce que je veux réaliser est d’obtenir des paramètres dans mon composant parent FROM routes enfants.

Par exemple, disons que ce sont mes routes:

const routes: Routes = [
  {
    path: 'parent',
    component: ParentComponent,
    pathMatch: 'prefix',
    children: [
      {
        path: ':id',
        component: ChildComponent
      }
    ]
  }
];

Je veux obtenir le paramètre id et l'utiliser dans mon ParentComponent . Donc j'essaie comme ceci:

export class ParentComponent implements OnInit {

  sub: any;
  constructor(
    private route: ActivatedRoute) {
    this.route = route;
   }

  ngOnInit() {

    this.sub = this.route.params.subscribe(params => {
     let id = params['id'];
     console.log(id);
   });

  }

}

Comme ça j'obtiens:

Undefined

Qu'est-ce que j'oublie ici?

12
Vassilis Pits

La ActivatedRoute a des accesseurs pour accéder aux informations sur son itinéraire parent/enfant.

Pour accéder au premier itinéraire enfant à partir du parent, vous utiliseriez:

this.route.firstChild.params

Si vous vouliez tous les itinéraires enfants, vous utiliseriez la propriété children. Ceci retourne un tableau de ActivatedRoute

this.route.children

Si vous étiez dans une route enfant et que vous aviez besoin des paramètres du parent:

this.route.parent.params

23
Brandon

Les paramètres enfants sont associés/enregistrés avec l'enfant ActivatedRoute . Ils ne sont pas disponibles sur ActivatedRoute du parent. Vous devez donc d'abord obtenir ActivatedRoute de l'enfant avec getter firstChild ou children.

Ensuite, le parent peut s’abonner aux modifications apportées aux paramètres enfants:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute }               from '@angular/router';
import { Subscription }                 from 'rxjs/Subscription';

export class ParentComponent implements OnInit, OnDestroy {
   private sub: Subscription;
   constructor(private route: ActivatedRoute) {}
   ngOnInit() {
      this.sub = this.route.firstChild.params.subscribe(
        params => console.log(params.id));
   }
   ngOnDestroy() {
      this.sub.unsubscribe();
   }
}

ou il peut obtenir un instantané des paramètres enfants:

import { Component }      from '@angular/core';
import { ActivatedRoute } from '@angular/router';

export class ParentComponent {
   constructor(private route: ActivatedRoute) {}
   someMethod() {
      console.log(this.route.firstChild.snapshot.params.id);
   }
}

Si vous souhaitez obtenir tous les enfants (par exemple, si vous avez plusieurs points de vente), utilisez ActivatedRoute.children ou ActivatedRouteSnapshot.children pour obtenir un tableau d'enfants ActivatedRoutes ou ActivatedRouteShapshots.

5
Mark Rajcok
this.route.snapshot.paramMap.get('id');
0
labu4bd
  this.router.events.subscribe(event => {
            if (event instanceof RoutesRecognized) {
                // let strId = event.state.root.firstChild.children[0].data;
                let a = event.state.root.firstChild.children.map((route) => {
                    while (route.firstChild) {
                        route = route.firstChild;
                    }

                    return route;
                });
                console.log('Title', a[0].data.title);
                this.meta.updateTitle(a[0].data.title);
            }
            if (event instanceof NavigationEnd) {
                (<any>window).gtag('config', this.googleAnalyticsCode, {
                    'page_title' : this.titleService.getTitle(),
                    'page_path': event.urlAfterRedirects
                });
            }
        });
0
atjoshi

En utilisant this.activatedRoute.snapshot.firstChild.params

0
gildniy

Il est très facile d'obtenir les paramètres enfants via ActivatedRoute. Toutefois, vous pouvez rapidement rencontrer des problèmes si vous modifiez l'enfant actuel.

D'abord quelques notes:

  • La propriété activatedRoute.firstChild est une instance ActivatedRoute et PAS une observable.
  • Notez également que activatedRoute.paramMap est un observable.

Voici comment vous pouvez rencontrer des problèmes:

  • Considérez un composant avec deux itinéraires enfants - et les composants correspondants - dans lesquels un seul est affiché à la fois (par exemple, une interface à onglets).
  • Si vous accédez à firstChild.paramMap dans votre gestionnaire ngOnInit, vous pourrez vous y abonner et surveiller les paramètres à mesure qu'ils changent. Cela va regarder et fonctionne très bien.
  • Si vous passez au deuxième onglet, puis de nouveau au premier, tout va casser. En effet, vous avez initialement souscrit paramMap sur une instance ActivatedRoute qui n'existe plus.
  • Important: Ce problème ne survient que si vous essayez d'accéder à la variable paramMap de l'enfant. Si vous essayez d'accéder à votre "propre" paramMap, ou si le composant enfant injecte également paramMap, tout ira bien.

La solution la plus propre à ce que j'ai trouvée est la suivante:

Remarque: Commencez par injecter router: Router en plus de route: ActivatedRoute.

const firstChildParams$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd),
                                                  startWith(undefined),
                                                  switchMap(e => this.route.firstChild!.paramMap));

Cela n'écoute que les événements NavigationEnd, après quoi une nouvelle firstChild sera disponible. En utilisant switchMap, vous n'avez pas à craindre de vous désabonner des anciennes cartes redondantes. De même, la valeur réelle de l'événement de navigation n'est jamais utilisée, et startWith est nécessaire pour pouvoir gérer les paramètres immédiatement la première fois.

J'ai rassemblé des choses utiles comme celle-ci dans un RouterHelperService que je peux injecter n'importe où, sans avoir à me souvenir de toute cette folie.


Un jour, je pourrais suggérer qu'il devrait y avoir un équivalent observable de firstChild, alors ce ne serait pas un problème. Cependant, cela introduirait peut-être encore plus de confusion dans d'autres scénarios!

0
Simon_Weaver