15-5 Observer les changements de paramètre de la route active
Imaginez que dans la barre de navigation, plutôt que simplement un lien Projets
, on avait un menu déroulant affichant les projets. Cliquer sur l'un des éléments nous redirigerais vers le projet en question.
Ce genre de cas de figure a le potentiel d'introduire un problème en lien avec le changement de route que nous allons explorer dans cette section.
Afficher la liste de projets dans un menu de navigation
Pour un accès rapide aux projets, imaginez que nous ayons un menu déroulant de type dropdown
contenant la liste des projets, plutôt qu'un simple lien.
-
Remplacez le lien de menu suivant
src/app/shared/components/navbar.ts<li class="nav-item">
<a class="nav-link" routerLink="/projets" routerLinkActive="active">Projets</a>
</li> -
Par un dropdown:
src/app/shared/components/navbar.ts<li class="nav-item" ngbDropdown>
<a class="nav-link dropdown-toggle" ngbDropdownToggle role="button" aria-expanded="false">
Projets
</a>
<ul class="dropdown-menu" ngbDropdownMenu>
@for(projet of projets; track projet.id) {
<li><a class="dropdown-item" [routerLink]="['/projets', projet.id]">{{projet.nom}}</a></li>
}
</ul>
</li>attentionIl vous faudra importer, à l'aide de WebStorm:
-
ngbDropdown
-
ngbDropdownToggle
-
ngbDropdownMenu
Soit trois directives en provenance de
ngBootstrap
. -
Vous aurez une erreur puisque la variable projets
n'existe pas. Il faut en effet récupérer les projets via L'API!
- Ajoutez une propriété
projets
src/app/shared/components/navbar.tsexport class Navbar {
protected projets: Projet[] = [];
} - Injectez
ProjetService
via le constructeursrc/app/components/navbar.component.tsexport class Navbar {
protected projets: Projet[] = [];
constructor(private projetService: ProjetService) {
}
} - Implémentez
OnInit
et récupérez la liste de projets lors de l'initialisationsrc/app/components/navbar.component.tsexport class Navbar implements OnInit {
protected projets: Projet[] = [];
constructor(private projetService: ProjetService) {
}
async ngOnInit(): Promise<void> {
this.projets = await this.projetService.obtenirTous();
}
}
Vous aurez maintenant un merveilleux menu déroulant!
Problème! 🚨
Le menu de navigation est fonctionnel et synchronisé, mais ne fonctionne pas comme attendu dans un cas bien précis.
Si vous êtes sur la page d'un projet (projet-detail
) et que vous tentez d'accéder à un autre projet à partir du menu de navigation, le composant n'est pas rechargé et donc le contenu ne change pas!
À noter: dans l'animation ici, vous verrez des éléments d'interface que vous n'avez pas, c'est normal, c'est une capture d'écran prise plus loin dans les notes, mais le comportement reste le même :)
La raison est que bien que l'URL change, c'est le même composant qui est associée à la route. Dans ce cas, Angular ne recharge pas le composant. Lorsqu'on rencontre cette situation, on peut "écouter" les changements au chemin de navigation.
S'abonner aux changements de la route active
Pour détecter les changements, on peut s'abonner à la route active et être "notifié" des changements aux paramètres.
Pour cela, plutôt que d'utiliser le snapshot
de la route et de ses paramètres, il est possible de s'abonner, via un observable, aux changements.
- Dans
ProjetDetail
, videz le contenu dengOnInit
et s'abonner à l'observablethis.route.params
viasubscribe
.src/app/features/projets/pages/projet-detail.tsasync ngOnInit(): Promise<void> {
this.route.paramMap.subscribe(async (params) => {
})
}
Angular utilise le concept d'observable à plusieurs endroits. Ici, on s'abonne à this.route.paramMap
et dès que des changements sont observés, la fonction passée en paramètre sera exécutée.
- Ensuite, on accès aux paramètres via
get()
de cette façon:src/app/pages/projets/projet-detail.page.tsasync ngOnInit(): Promise<void> {
this.route.paramMap.subscribe(async (params) => {
const routeParam = params.get('id');
console.log(routeParam);
})
}
Vous pouvez essayer dans votre navigateur et devriez voir les différents id
s'afficher dans la console à mesure que vous changez de page. Assurez-vous d'être sur la page de détail d'un projet.
Adapter le chargement des projets à la nouvelle logique
La logique de détection de changements aux paramètres est bien en place, mais on doit ramener l'affichage des projets!
- Pour se faire, plutôt que le
console.log
, associez le nouvel identifiant à la propriétéid
de la classe.
async ngOnInit(): Promise<void> {
this.route.params.subscribe(async (params) => {
if(params['id']) {
this.id = params['id'];
}
})
}
- Encapsulez la logique de chargement des projets dans une fonction
chargerProjets()
async chargerProjet() {
if(this.id) {
this.projet = await this.projetService.obtenir(this.id);
}
}
- Finalement, appelez la fonction de chargement lorsque l'identifiant change.
async ngOnInit(): Promise<void> {
this.route.paramMap.subscribe(async (params) => {
const routeParam = params.get('id');
if(routeParam){
this.id = +routeParam;
await this.chargerProjet();
}
});
}
- Profit! (le tout devrait maintenant fonctionner 🙂)