Angular - Le routing

Vous cherchez à comprendre comment fonctionne le routing aveC Angular ? vous êtes à la bonne adresse !

Le routeur Angular permet la navigation d’une vue à l’autre de l’application lorsque l’utilisateur interagit avec le DOM, dans cet article nous allons aborder ce sujet en détails.

Qu'est-ce que le routing ?

Avant de rentrer dans le vif du sujet, un peu d’histoire !

Historique

Pendant longtemps, pour naviguer sur internet, le visiteur cliquait sur un lien pour recharger intégralement une nouvelle page. Ce n'est qu'au milieu des années 2000 (Entre 2002 et 2005) qu'une nouvelle API Javascript fait son apparition dans les navigateurs internet: XMLHttpRequest (souvent appelé Ajax).

L'utilisation de cette API permet de télécharger des données depuis un serveur distant afin de mettre à jour du contenu sans avoir à recharger intégralement la page dans le navigateur.

Il restait néanmoins un problème: il était impossible de modifier l'adresse courante dans le navigateur. Il était donc compliqué pour un visiteur de se situer ou de partager son contenu. Les développeurs ont donc détourné l'utilisation de l'anchor dans les adresses pour créer des pseudo-adresses du type:
https://www.mon-super-site.fr/#/blog/article/21

Pour contrer correctement le problème, il a fallu attendre l'arrivée de l'API History. Elle permet le changement de l'adresse courante dans le navigateur et de manipuler l'historique depuis du code javascript.

On a donc vu à partir de là apparaitre des librairies de routing fonctionnelles et les premières SPA (Single Page Application).

Exemple d'utilisation de l'API History
Manipulation d'URL via l'API History

Définition

Le routing correspond au fait d'associer une action à un certain chemin d'URL

Dans le cas d'Angular, il s’agit en réalité d’une instruction d’affichage, car une route associe une adresse à un component.

Créer des routes

Si votre projet est créé via la CLI, on vous proposera le routing pour votre application. Si vous avez acceptez, un fichier app-routing.module.ts sera créé dans votre projet.

Voici un exemple de fichier app-routing.module.ts :

1
2
3
4
5
6
7
8
9
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { FirstComponent } from './first/first.component';
import { SecondComponent } from './second/second.component';
 
const routes: Routes = [
   { path: 'exemple-route', component: FirstComponent },
   { path: '', component: SecondComponent }
];
app-routing.module.ts

Dans notre constante "routes", on retrouve la configuration des routes. La propriété "path" contient le nom de la route qui sera dans l’URL.

La deuxième propriété de l’objet route correspond au component qui sera affiché lors du chargement de cette URL.

Par exemple, dans le code ci-dessus on a défini les routes suivantes :

http://localhost:4200/exemple-route
http://localhost:4200/

La première URL chargera le component FirstComponent et la deuxième chargera SecondComponent.

Cette configuration est à charger via le RouterModule, fourni par Angular, dans votre AppModule. Tout cela est fait pour vous, si vous passez par la CLI pour ajouter le routing.

Naviguer à travers les routes

Maintenant, voyons comment naviguer à travers nos différentes routes.

Naviguer via un routerLink

Nous allons utiliser la directive routerLink qui est l’équivalent de l’attribut href de la balise <a>, ce qui nous permettra de naviguer dans l’application.

Sauf qu'en réalité, l’attribut href rechargerait la page via le navigateur ce qui n’est pas ce que l’on recherche.

2 syntaxes sont possibles. Les deux liens de l’exemple ci-dessous ont le même comportement.

1
2
3
4
5
6
7
8
9
10
<nav>
  <ul>
    <li>
      <a routerLink="/contact/">Articles</a>
    </li>
    <li>
      <a [routerLink]="['/contact', id]">Contactez-nous</a>
    </li>
  </ul>
</nav>
exemple.component.html

Naviguer avec l'objet Router

Il existe aussi une deuxième option de navigation qui permet de naviguer depuis la partie TS du component. Pour cela, il suffit d’injecter le service Router dans le composant.

C’est avec la méthode 'navigate' que nous déclenchons la navigation vers la nouvelle adresse passée en paramètre.

1
2
3
4
5
6
7
8
9
10
11
12
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'router-demo';
  constructor(private router: Router){}
  navigateToContact(){
    this.router.navigate(['/contact']);
  }
}
app.component.ts

Notez qu'il faut passer un tableau en paramètre.

Les paramètres de route

Imaginons que nous avons un service qui permet de gérer une liste de pokémons. Ce service nous permet d'obtenir les données concernant un Pokemon en passant l'id en paramètre.

Voici à quoi ressemblerait un tel service :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Injectable } from '@angular/core';
 
@Injectable({
 providedIn: 'root'
})
export class  PokemonService {
 
  pokemons = [
    {
      id: 1,
      name: 'Salameche',
      status: 'En forme'
    },
    {
      id: 2,
      name: 'Pikachu',
      status: 'KO'
    },
    {
      id: 3,
      name: 'Bulbizar',
      status: 'En forme'
    }
  ];
 
  constructor() { }
 
  getAllPokemons(){
    return this.pokemons;
  }

  getPokemonById(id: number){
    return this.pokemons.find(p => p.id === id);
  }
}
pokemon.service.ts

On souhaite de notre côté, créer un component pour afficher un pokémon sur une page de détails. Dans un cas comme celui-ci, nous aurons besoin des paramètres de routes.

Créons donc une route dans notre fichier app-routing.module.ts en ajoutant deux points ':' pour indiquer que le fragment de route qui suit sera un paramètre.

1
2
3
4
const routes: Routes = [
 { path: 'pokemons', component: ListPokemonComponent },
 { path: 'pokemon/:id', component: SinglePokemonComponent },
];
app-routing.module.ts

Ainsi peu importe le chemin: 'pokemon/a' ou 'pokemon/1' etc… cela chargera le component SinglePokemonComponent.

Notre component ressemblera de base à quelque chose comme ça :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component({
  selector: 'app-single-pokemon',
  templateUrl: './single-pokemon.component.html',
  styleUrls: ['./single-pokemon.component.scss']
})
export class SinglePokemonComponent implements OnInit {

  name: string = '';
  status: string = '';

  constructor(private pokemonService: pokemonService) { }

  ngOnInit() {
  }
}
single-pokemon.component.ts
1
2
<p>{{ name }}</p>
<p>{{ status }}</p>
single-pokemon.component.html

Maintenant, nous allons injecter dans notre component le service ActivatedRoute pour récupérer l’id dans l’URL et l'utiliser dans le service PokemonService.

Ce qui devrait nous donner quelque chose comme ça :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component({
  selector: 'app-single-pokemon',
  templateUrl: './single-pokemon.component.html',
  styleUrls: ['./single-pokemon.component.scss']
})
export class SinglePokemonComponent implements OnInit {

  name: string = '';
  status: string = '';

  constructor(private pokemonService: PokemonService,
    private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.route.paramMap.subscribe((params: ParamMap) => {
      const id = parseInt(params.get('id'));
      const pokemon = this.pokemonService.getPokemonById(id);
      this.name = pokemon.name;
      this.status = pokemon.status;
    }); 
  }
}
single-pokemon.component.ts

Petite explication : depuis l’objet route (d’activatedRoute) nous avons un objet paramMap qui est de type Observable et qui contient une carte des paramètres dont on va pouvoir récupérer la valeur !

Donc nous récupérons la valeur du paramètre 'id' en souscrivant à cet Observable et nous contactons le service avec cet id.

Pour finir, on récupère les noms et statuts pour les assigner à nos attributs de composants, afin qu'il soit capable de les afficher.

On peut donc maintenant accéder à notre page de détails d'un pokemon via le router :

1
2
// Crée un lien vers la page de détails du pokémon 1
<a [routerLink]="['/pokemon', 1]"></a>
exemple.component.ts

Redirection

Il est aussi possible de rediriger l’utilisateur avec le routeur d'Angular.

Par exemple si l’utilisateur renseigne une URL qui n’existe pas au sein de l’application nous pourrions le rediriger vers une page 404 personnalisée.

Pour ce faire, nous allons utiliser la propriété 'redirectTo' dans la définition de nos routes :

1
2
3
4
const routes: Routes = [
  { path: 'not-found', component: NotFoundComponent },
  { path: '**', redirectTo: 'not-found' }
]
app-routing.module.ts

La première route est la route directe vers le component 404. La seconde est une route 'wildcard' qui redirigera toute route inconnue vers la page 404.

Ainsi quand l’utilisateur renseignera une URL qui n’existe pas il sera redirigé vers le chemin 'not-found' qui affichera la page 404.

Notions avancées

Malheureusement nous ne verrons pas tout dans cet article car il est destiné aux débutants et se limite donc aux notions de base.

Sachez toutefois qu'il existe des concepts tels que les routes imbriquées, le lazyloading, les guards et les resolvers. En attendant nos prochains articles je vous conseille de lire la documentation Angular pour découvrir tout cela !

Sources

Auteur

image auteur
Lucas BENTO-VERSACE Alternant chez Codewise / Étudiant en développement web lucas.bentoversace@ynov.com
"Alternant chez Codewise, passioné par l'informatique et les technologies depuis mon plus jeune âge. J'ai découvert le monde du web et depuis je ne m'en lasse pas ! Fan de jeux vidéos, de sports et de musiques. "