Activer/Désactiver des Routes dynamiquement avec Angular


Le routeur d’Angular permet l’activation et la désactivation des routes de votre application Angular avec le concept de Guards. Le principe est simple, si une route possède une Guard, elle sera interrogée à chaque fois que la route sera demandée.

Mais qu’est-ce qu’une Guard ?

Une Guard est tout simplement une méthode qui renvoie true ou false en fonction de l’expression qu’on lui demande de vérifier. Pour donner un peu plus de souplesse à leur utilisation, Angular nous permet de renvoyer plusieurs types de données depuis nos Guard : soit un Observable<boolean>, soit une Promise<boolean> ou tout simplement un boolean.

Définition des Guards

Comme souvent avec Angular, il existe plusieurs manières de définir une Guard. La plus simple étant d’utiliser une fonction que l’on va définir parmi nos providers du module concerné.

Notre provider doit posséder un nom et une valeur comme dans l’exemple ci-dessous.

À noter qu’ici, on utilise une valeur dans notre provider (avec l'attribut useValue) mais un provider peut se déclarer de plusieurs manières. Plus d’informations sont disponibles dans la documentation.

Pour appliquer notre Guard, il suffit d’indiquer dans la route concernée que son activation dépend de la Guard du nom choisi. Pour cela, les routes possèdent un attribut canActivate qui est de type Array. Il est en effet possible de mettre plusieurs Guards à une seule route. Évidemment, toutes les Guards seront vérifié et la route ne sera active que si elle renvoient toutes true.

Comme notre Guard provider a été définie comme une valeur avec un nom en chaîne de caractères, il faut le passer à la route sous la même forme: une chaîne de caractères.

Il est possible d’ajouter n’importe quel type de comportements dans la méthode définie dans notre provider via useValue mais nous allons vite être limités. Pour cela, Angular permet de définir directement une class comme Guard sur une route. Dans ce cas là, l’attribut utilisé est le même, mais nous allons importer le service et le passer directement à notre tableau.

Dans le cas d’une class, l’utilisation des Guards reste très proche mais le service qui va désormais déterminer l’activation de la route ou non doit posséder plusieurs spécificités. Tout d’abord la class doit implémenter l’interface CanActivate. Cette interface impose la définition d’une méthode canActivate() qui sera, comme son nom l’indique, la méthode utilisée pour vérifier l’accès à la route. Cette méthode doit, là aussi, renvoyer un boolean (directement ou via une Promise ou un Observable) et reçoit deux paramètres : route: ActivatedRouteSnapshot et state: RouterStateSnapshot. Ils apportent toute les informations nécessaires pour vérifier l’accès à la route dans le contexte courant.

L’exemple ci-dessus reste assez simple mais permet de se rendre compte comment les Guards peuvent être mises en place dans une application Angular.

Les autres Guards

Si la Guard canActivate est la plus évidente (et la plus usuelle), il existe en tout 4 Guards disponibles pour les routes dans Angular.

  • canActivate : Evidemment, nous venons d’en voir tous les détails !
  • canActivateChild : Fonctionne de la même manière que canActivate mais, comme son nom l’indique, s’applique sur les routes filles uniquement. Cela peut être très pratique pour désactiver l’accès à toutes les sous-pages d’une route. La documentation sur cette Guard est similaire à canActivate.
  • canDeactivate : Fonctionnant de la même manière que canDeactivate, son miroir existe également. Là encore, la documentation est très similaire.
  • canLoad : Fonctionnant toujours sur le même schéma, canLoad permet de gérer le chargement (ou non) des modules en lazy loading. Car oui, Angular permet nativement de charger dynamiquement des modules selon les besoins de l’application. Je ne vais pas détailler trop ce fonctionnement ici puisqu’il mériterait un article dédié.

Conclusion

Les Guards fournies par Angular sont le bon moyen de gérer les routes selon l’état de notre application, elle sont simples d’utilisation et permettent une bonne scalabilité lors de leur utilisation. Nous y reviendrons dans un prochain article mais la possibilité de désactiver le chargement de modules avec canload est également très intéressant d’un point de vue performance.

Pour aller plus loin, voici un article très bien fait de Thoughtram qui détaille chacune des Guards plus largement. La documentation a également été récemment mise à jour et permet de mieux comprendre l’utilisation que dans la version précédente.