Aller au contenu principal

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.

  1. 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>
  2. 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>
    attention

    Il 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!

  1. Ajoutez une propriété projets
    src/app/shared/components/navbar.ts
    export class Navbar {
    protected projets: Projet[] = [];
    }
  2. Injectez ProjetService via le constructeur
    src/app/components/navbar.component.ts
    export class Navbar {
    protected projets: Projet[] = [];

    constructor(private projetService: ProjetService) {

    }
    }
  3. Implémentez OnInit et récupérez la liste de projets lors de l'initialisation
    src/app/components/navbar.component.ts
    export 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!

Imgur

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 :) Imgur

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.

  1. Dans ProjetDetail, videz le contenu de ngOnInit et s'abonner à l'observable this.route.params via subscribe.
    src/app/features/projets/pages/projet-detail.ts
    async ngOnInit(): Promise<void> {
    this.route.paramMap.subscribe(async (params) => {
    })
    }
info

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.

  1. Ensuite, on accès aux paramètres via get() de cette façon:
    src/app/pages/projets/projet-detail.page.ts
    async ngOnInit(): Promise<void> {
    this.route.paramMap.subscribe(async (params) => {
    const routeParam = params.get('id');
    console.log(routeParam);
    })
    }
info

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!

  1. Pour se faire, plutôt que le console.log, associez le nouvel identifiant à la propriété id de la classe.
src/app/features/projets/pages/projet-detail.ts
async ngOnInit(): Promise<void> {
this.route.params.subscribe(async (params) => {
if(params['id']) {
this.id = params['id'];
}
})
}
  1. Encapsulez la logique de chargement des projets dans une fonction chargerProjets()
src/app/features/projets/pages/projet-detail.ts
async chargerProjet() {
if(this.id) {
this.projet = await this.projetService.obtenir(this.id);
}
}
  1. Finalement, appelez la fonction de chargement lorsque l'identifiant change.
src/app/features/projets/pages/projet-detail.ts
async ngOnInit(): Promise<void> {
this.route.paramMap.subscribe(async (params) => {
const routeParam = params.get('id');
if(routeParam){
this.id = +routeParam;
await this.chargerProjet();
}
});
}
  1. Profit! (le tout devrait maintenant fonctionner 🙂)

Level Up