Blog ENI : Toute la veille numérique !
🎃 Jusqu'à -30% sur les livres en ligne, vidéos et e-formations.
Code : GHOST30.
Cliquez ici !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Angular
  3. Le routage
Extrait - Angular Développez vos applications web avec le framework JavaScript de Google (3e édition)
Extraits du livre
Angular Développez vos applications web avec le framework JavaScript de Google (3e édition) Revenir à la page d'achat du livre

Le routage

Introduction

Dans ce chapitre, la navigation au sein d’une application va être abordée. Pour cela, les notions de route et de navigation vont être décrites. Pour aller plus loin dans les détails du routage avec Angular, les notions de Resolver et d’outlets nommées feront également l’objet d’une étude.

Définir les routes d’une application

La navigation au sein d’une application Angular s’effectue grâce à un système de route qui doit être définie. Une route dans sa forme la plus basique est l’association d’un composant et d’une URL. Lorsque cette URL est demandée, le module de routage effectue le rendu du composant associé.

Pour effectuer cette association d’une URL à un composant, il faut définir une variable de type Routes. Ce type est déclaré comme étant un tableau dont chaque élément est un objet de type Route.

Une route est donc composée d’un attribut path qui représente l’URL (relative ou absolue) associée à cette route et d’un attribut component qui est le composant à charger lorsque cette route est appelée.

import { Routes } from '@angular/router'; 
import { PommeListComponent } from './pomme-list/
pomme-list.component'; 
 
export const ROUTES : Routes = [ 
  { path: 'pommes', component: PommeListComponent } 
]; 

Dans l’exemple ci-dessus, une route est déclarée afin que, lorsque l’URL ’pommes’ est appelée, ça soit le composant PommeListComponent qui est chargé. Il faut cependant enregistrer cette route afin qu’elle soit utilisable.

Il est également possible d’effectuer des redirections. C’est très utile pour définir des routes par défaut, par exemple. Pour cela, au lieu d’utiliser l’attribut component de l’objet Route, il faut utiliser l’attribut redirectTo. Cet attribut se remplit en utilisant la valeur d’un attribut path existant du tableau de routes. Lorsque cet attribut est utilisé, il est également...

Le rendu de composant

Afin que le routeur puisse effectuer le rendu du composant, il faut en tout premier lieu enregistrer les routes déclarées dans le tableau ROUTES.

Cela se fait au niveau de la déclaration du module de l’application. Il faut pour cela ajouter le module de routage, RouterModule, à l’application. Ce module doit être importé en utilisant la méthode forRoot qu’il expose. Cette méthode prend en paramètre un objet de type Routes. Il faut donc lui passer le tableau de routes défini précédemment.

import { RouterModule } from '@angular/router'; 
import { ROUTES } from './app.routes'; 
import ... 
 
@NgModule({ 
  declarations: [ 
    ... 
  ], 
  imports: [ 
    BrowserModule, 
    RouterModule.forRoot(ROUTES) 
  ], 
  providers: [...], 
  bootstrap: [...] 
}) 
export class AppModule { } 

Dans l’exemple de déclaration de module ci-dessus, l’import du module RouterModule se fait en utilisant un objet de type Routes venant du fichier app.routes.ts. Ce fichier contient le code de l’exemple précédent. C’est une bonne pratique de définir les routes dans un fichier séparé, car la définition de celles-ci grandit très vite dès qu’une application dispose de plusieurs vues.

Il est maintenant nécessaire de préciser au module de routage où il doit faire le rendu des composants associés aux routes. Pour cela, il faut utiliser la directive RouterOutlet dans le composant principal de l’application, en ajoutant la balise router-outlet dans le template. Le rendu du composant de la route active se fera donc au niveau de cette balise :

<header> ...

Naviguer dans son application

Afin de naviguer dans une application en utilisant le module de routage, il existe deux solutions. Premièrement, il est possible de naviguer en utilisant des liens hypertextes HTML (balise « a »). Pour ce faire, il faut utiliser la directive RouterLink.

Pour le cas des URL non dynamiques, il suffit d’affecter à cette directive la valeur de la propriété path de la route associée. Par exemple, <a routerLink="/pommes"> pointera vers la route pommes définie dans le tableau de routes.

Pour le cas d’URL dynamiques, cette directive prend en paramètre un tableau de valeurs. Ces valeurs correspondent au chemin de la route visée par ce lien. Par exemple, pour naviguer vers la page du détail d’une des variétés de pomme de l’exemple précédent, il est possible d’utiliser la syntaxe suivante :

<ul> 
  <li *ngFor="let pomme of pommes"> 
    {{pomme.id}} 
    <a [routerLink]="['/pomme', pomme.id]">{{pomme.name}}</a> 
  </li> 
</ul> 

Le lien ci-dessus pointera vers la page de détail d’une variété de pomme, et la partie dynamique de la route sera remplie avec l’identifiant de la variété de pommes sur laquelle l’utilisateur a cliqué.

Il est également possible d’utiliser l’attribut natif href de la balise HTML « a » cependant, cela impliquerait un chargement de la page, rendant l’expérience utilisateur moins agréable.

La deuxième manière d’effectuer une navigation est de le faire directement dans le code d’un composant. Pour cela, il faut injecter une instance de l’objet Router...

Récupération des données de routage

Afin d’obtenir des informations concernant la route active au sein du composant, il faut injecter l’objet ActivatedRoute. Cet objet contient notamment des informations sur les paramètres passés à la route lors de la navigation.

Pour récupérer ces informations, il est possible de passer par la propriété snapshot de cet objet. Cette propriété contient elle-même une propriété params contenant tous les paramètres passés à la route lors de la navigation.

Import ... 
import { ActivatedRoute, Router } from '@angular/router'; 
 
@Component({...}) 
export class PommeDetailsComponent implements OnInit { 
 
  pomme: Pomme; 
  constructor(private pommeService: PommeService, 
              private route: ActivatedRoute, 
              private router: Router) { } 
 
 ngOnInit() { 
    const id = +this.route.snapshot.params['id']; 
    this.pommeService.getPomme(id) 
                     .subscribe(pomme => this.pomme = pomme); 
  } 
 
  goBack() { 
    this.router.navigate(['pommes']); 
  } 
} 

Dans l’exemple, la classe ActivatedRoute est injectée dans le constructeur du composant. Dans la méthode d’initialisation, on récupère le paramètre ’id’ dans l’objet snapshot.params de l’ActivatedRoute. Le symbole « + » au niveau de l’affectation à la constante id sert à caster le paramètre id en number. En effet, les paramètres...

Outlet nommé

1. Définir des outlets nommés

Le module de routage d’Angular permet de disposer de plusieurs outlets au sein d’un même composant (pour rappel, un outlet est une instance de la directive RouterOutlet et permet de spécifier au module de routage où il doit rendre le composant associé à la route). Grâce à cette fonctionnalité, il est possible de rendre plusieurs routes en même temps, de manière totalement indépendante sur une même vue. Ce mécanisme peut être utilisé afin de créer un layout d’application. Avec une vue pour le menu, une autre pour le corps de l’application, une autre pour l’en-tête, etc.

Pour utiliser cette fonctionnalité, il est donc nécessaire de pouvoir différencier les outlets. Pour cela, il faut utiliser l’attribut name de la directive RouterOutlet. Par exemple, pour un outlet nommé list et un outlet nommé detail, les balises deviennent donc les suivantes :

<router-outlet name="list"></router-outlet> 
<router-outlet name="detail"></router-outlet> 

Il faut également définir des routes utilisant ce mécanisme. Pour cela, il faut utiliser la propriété outlet des objets Route qui sont enregistrés dans l’application. Cette propriété doit être remplie avec la valeur utilisée dans l’attribut name de la directive RouterOutlet.

export const ROUTES: Routes = [ 
  { 
    path: 'pommes/:page', 
    component: PommeListComponent, 
    outlet: 'list' 
  }, 
  { 
    path: 'pomme/:id', 
    component: PommeDetailsComponent, 
    outlet: 'detail' ...

Resolver

Le module de routage d’Angular permet de passer des données à la vue via deux mécanismes. Le premier concerne les données statiques. Pour ajouter des données statiques à une vue, il suffit d’ajouter une propriété data lors de la création de la route :

export const ROUTES: Routes = [ 
  { 
    path: '', 
    redirectTo: '/(list:pommes/0)', 
    pathMatch: 'full' 
  }, 
  { 
    path: 'pommes/:page', 
    component: PommeListComponent, 
    outlet: 'list' 
  }, 
  { 
    path: 'pomme/:id', 
    component: PommeDetailsComponent, 
    outlet: 'detail', 
    data: { 
      pomme: new Pomme(12, 'staticPomme', true, true, true) 
    } 
  } 
]; 

Dans l’exemple ci-dessus, sur la dernière route, la propriété data a été ajoutée à la définition de la route. Un objet Pomme est donc maintenant disponible dans les propriétés de la route passée au composant. En revanche, celle-ci ne sera jamais modifiée, qu’importe la valeur des paramètres de la route.

Pour passer à la vue des données dynamiques, Angular introduit la notion de resolver, permettant d’associer des données à des routes.

Pour créer un resolver, il faut créer une classe qui implémente l’interface Resolve. Cette interface est générique et doit être typée avec le type de retour des données à résoudre. De plus, les resolvers doivent être décorés...