web-dev-qa-db-fra.com

Angular 4 Composant ngOnInit non appelé à chaque demande de route

Je viens tout juste de commencer à plonger dans Angular 4 en provenance de Angular 1.5. Je travaille avec des itinéraires utilisateur et en extrayant des données d'API d'un service dans un composant utilisateur. 

Le composant semble rester statique contrairement aux contrôleurs dans 1. * où ils ont été actualisés à chaque demande.

Est-il possible quand même que la fonction ngOnInit soit appelée à chaque nouvelle demande de route?

Ma classe de composant utilisateur:

// url structure: /user/:id
export class UserComponent implements OnInit {

    constructor(private route: ActivatedRoute) {}

    ngOnInit() {

      // doesn't log new id on route change
      let id = this.route.snapshot.params['id'];
      console.log(id);

      this.route.params
        .switchMap(params => this.userService.getUser(params['id']))
        .subscribe(user => {
          // logs new id on route change
          let id = this.route.snapshot.params['id'];
          console.log(id);

          this.user = user
        });
    }
}

METTRE À JOUR:

J'ai trouvé une solution qui, à mon avis, convient le mieux à mon scénario. Sur la base de plusieurs réponses et commentaires à ma question et d'une enquête plus approfondie, s'abonner à l'itinéraire semble être la voie à suivre. Voici mon composant mis à jour:

export class UserComponent {

  user;
  id;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute
  ) {}


  ngOnInit() {
    this.route.params
      .subscribe(params => this.handleRouteChange(params));
  }

  handleRouteChange(params) {
    this.id = params['id'];

    switch (this.id) {
      case '1':
        console.log('User 1');
        break;

       case '2':
        console.log('User 2');
        break;

       case '3':
        console.log('User 3');
        break;
    }

    this.userService.getUser(this.id).
      subscribe(user => this.user = user);
  }

}
7
Rob

Angular préfère, par défaut, réutiliser le même composant au lieu d’en installer un nouveau si la route est la même mais les paramètres changent.

Bonnes nouvelles ! Il s'agit d'un comportement personnalisable. Vous pouvez forcer l'instanciation d'une nouvelle instance de composant en implémentant votre propre RouteReuseStrategy :

export class MyRouteReuseStrategy extends DefaultRouteReuseStrategy {
  shouldReuseRoute(next: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
    let name = next.component && (next.component as any).name;
    return super.shouldReuseRoute(next, current) && name !== 'UserComponent';
  }
}

dans votre module:

@NgModule({
  ...
  providers:[{
      provide: RouteReuseStrategy,
      useClass: MyRouteReuseStrategy}]
  ...
})
export class AppModule {}

(ce code provient plus ou moins de de cet article , en particulier de la vérification de la propriété name qui pourrait ne pas être très précise ...)

Notez qu’il peut y avoir un inconvénient en termes de performances lors du rétablissement du même composant. Dans ce cas, vous feriez peut-être mieux d'utiliser les propriétés observables au lieu de l'instantané.

2
n00dl3

L'URL ressemble-t-elle à "...? Id = 1" ou "../:id" et vous souhaitez que le composant enregistre l'identifiant chaque fois que le paramètre GET est modifié? On parle du problème ici . Une meilleure solution que j'ai trouvée est ici . Je ne l'ai pas testé moi-même mais cela devrait fonctionner. 

Le deuxième lien montre comment souscrire à un changement d’itinéraire dans un composant, ce qui, je pense, est essentiellement ce que vous essayez de faire. Cela vous permettra de gérer un changement de paramètre GET dans ngOnInit. Je ne sais pas si la route subscribe sera exécutée lorsque vous accédez initialement à l'URL. Vous souhaiterez peut-être que la fonction qui gère l'événement de route appelle doCheck() et remplace ngOnInit en ngAfterContentInit.

ngOnInit ne fonctionne que sur détection de changement , et un changement GET semble ne pas le déclencher, ce qui me surprend. 

Tl; dr - Abonnez-vous à l'événement de changement d'itinéraire dans le constructeur et créez une fonction qui gère un événement émis. La fonction devrait contenir la logique que vous avez dans ngOnInit ().

0
Michael

Bonjour, vous devez utiliser switchMap comme ceci:

this.sub = this.route.paramMap
  .switchMap((params: ParamMap) =>
  this.firebaseService.getProductsByCategory(params.get('category'))).subscribe(products => {
  this.products = products;
  this.count = products.length;
});

Ce travail pour moi.

0
Francisco