04 - Le Router
Introduction
Cette quête aborde un concept clé d'Angular, le router. Angular étant un framework conçu pour développer des applications de type SPA (Single Page Application), donc sans rechargement de page, il est indispensable d'utiliser un router pour naviguer au sein de l'application et gérer l'affichage des différentes pages.
Avant de démarrer, assure-toi d'avoir terminé les quêtes suivantes👇
Objectifs
✅ Comprendre l'intérêt du router ✅ Créer 3 routes pour naviguer entre les composants
Le Router, pourquoi ?
Avant l'arrivée des applications SPA, lorsqu'on souhaitait naviguer d'une page à une autre, on utilisait une balise <a> avec l'attribut href qui ciblait la page voulue.
Par exemple :
<a href="page/contact.html">
Lors du clic sur ce lien, l'url dans la barre d'adresse du navigateur change pour prendre la valeur : page/contact.html. Une requête est ainsi envoyée au serveur qui nous restitue la page demandée. Cette façon de procéder implique un rechargement complet du site. Bien mais pas top 😚
Ça, c'était avant ! Tu as sûrement remarqué qu'une fois ton application Angular démarrée ou buildée (ng serve ou ng build), tu n'as plus qu'un seul fichier .html : index.html.
C'est le seul fichier .html qui est gardé, car il s'agit du point d'entrée de ton application. Le chargement et l'initialisation d'Angular se font à travers ce fichier (pour info : les autres fichiers .html sont intégrés dans le code Typescript).
Oui mais si on a plus de pages, comment qu'on fait donc ? 🥸
Toutes tes "pages" vont devenir des composants (qui incluent du HTML, du CSS, du TS et probablement d'autres composants).
✅ C'est le router Angular qui va, pour une route, t'afficher le composant voulu.
Par exemple :
Lorsqu'on navigue sur
/contact, je veux que le composantContactComponentsoit affiché.
Tu pourras ainsi choisir les composants qui restent affichés sur la page et ceux qui doivent changer. D'ailleurs, on ne parle plus vraiment de "page", mais plutôt de "view".
Qu'est-ce qu'une route ?
Une route en Angular, c'est une partie de l'url. Si on prend cette url comme exemple : https://angular.io/guide/router, la route pour afficher la page est /guide/router.
Le router s'appuie sur l'url de ton navigateur pour déterminer quel composant doit être affiché. Une application est composée d'un ensemble de routes.
Une route est composée de plusieurs propriétés, dont :
-
path: qui correspond à l'url, par exemplecontact -
component: c'est le composant que vous voulez afficher pour lepath: 'contact', exemple : ContactComponent
Ce qui nous donnera une route définie comme ceci :
[...]
{
path: 'contact',
component: ContactComponent
},
[...]
Ok, mais où est-ce que je choisis l'emplacement de mon composant ?
C'est la directive RouterOutlet qui va déterminer où notre composant sera affiché. Par exemple, je souhaite que mon HeaderComponent et FooterComponent ne se rechargent pas lorsque je change de vue, et que mes composants (affichés selon une route spécifique) soient affichés entre le HeaderComponent et FooterComponent. J'ajoute donc la directive RouterOutlet entre les deux composants dans mon fichier app.component.html :
<app-header></app-header>
<router-outlet></router-outlet>
<!-- les composants définis dans le router seront rendus ici -->
<app-footer></app-footer>
Pour naviguer entre mes pages, j'utilise toujours des href ?
Noooon ! 🥳 Il faut utiliser la directive RouterLink et lui donner le chemin de la route. Exemple :
<a [routerLink]="['/contact']">CONTACT</a>
Place à la pratique
Maintenant que tu sais créer des projets et composants Angular à la vitesse de la lumière, nous allons créer un projet de test pour s'échauffer avant le challenge 😈 : crée un nouveau projet Angular RoutingTest.
Chaque nouveau projet créé via la commande ng new intègre un système de routage par défaut depuis la version 17 d'Angular.
Et bien ça permet :
-
L'installation du module
@angular/router -
La création d'un fichier
app.routes.ts(qui va servir à lister nos routes)
import { Routes } from '@angular/router';
export const routes: Routes = [];
- La création d'un fichier
app.config.tsqui sert à centraliser la configuration des routes de l'application définies dans le fichierapp.routes.tsen les passant à la fonctionprovideRouter().
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes)]
};
Essaye de bien suivre chaque étape avant d'aller voir le code du fichier
Zébartii 🥳
-
Crée deux nouveaux composants
homeetcontactavec le CLI (on utilise le html généré par défaut) -
Dans le tableau
routesdu fichierapp.routes.ts, déclare un objet pour chaque route que tu veux créer, un pour chaque route -
Le premier objet a pour propriété
pathavec pour valeur la chaîne de caractères'home', ainsi qu'une propriétécomponentégale àHomeComponent. -
Le deuxième objet aura pour chemin
contact, et comme composantContactComponent
Ton fichier app.routes.ts devrait ressembler à ceci :
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ContactComponent } from './contact/contact.component';
export const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'contact', component: ContactComponent },
];
- Supprime ensuite le contenu généré par défaut du fichier
app.component.html - Ajoute un menu pour naviguer entre
/homeet/contactà l'aide de la directiveRouterLink - Ajoute en-dessous de ton menu la directive
RouterOutlet
→ Ton fichier app.component.html devrait ressembler à ceci (un menu très moche) :
<ul>
<li>
<a [routerLink]="['/home']">HOME</a>
</li>
<li>
<a [routerLink]="['/contact']">CONTACT</a>
</li>
</ul>
<router-outlet></router-outlet>
Pour utiliser [routerLink]dans un template, tu dois l'ajouter dans le tableau des imports du composant lié :
import { Component } from '@angular/core';
import { RouterLink, RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, RouterLink],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
title = 'routing-test';
}
Tu peux maintenant lancer ton application avec le CLI et tester ton menu :
- Lorsque tu cliques sur "HOME", tu devrais voir "Home works !" sur ta page
- Lorsque tu cliques sur "CONTACT", tu devrais voir "Contact works !" sur ta page
Ouvre l'inspecteur d'élément et observe ce qu'il se passe en-dessous du tag router-outlet></router-outlet> lorsque tu navigues entre /contact et /home
Angular ajoute/retire automatiquement le tag correspondant à ton composant ! Plutôt stylé 😎
Et "Vwala" 🎉🎉 tu as mis en place une navigation de type SPA au sein de ton application !
Challenge 💪
Fais-moi naviguer ⛵️
Pour réaliser ce challenge, repars de l'app Angular que tu as créée dans la précédente quête :
Le but de ce challenge est d'afficher un menu pour naviguer entre le composant sign-up et le composant user-profile
- Crée un composant
menuqui contiendra deux liens : un vers/signupet l'autre vers/user - Crée le routeur avec 3 routes, une sur
signup, une suruseret une par défaut qui affiche le composantuser-profile - Le composant
appne doit contenir que le composantmenuet la directiverouter-outlet - Poste le lien vers ton repository en guise de solution.
Critères de validation ✅
- Le composant
menuest dans le composantapp - Les composants
sign-upetuser-profilene sont plus dans le composantapp - La directive
RouterOutletest utilisée dans le composantapp - Le fichier
app.routes.tsest correctement configuré pour afficher le composantsign-uplorsqu'on navigue vers/sign-up - Le fichier
app.routes.tsest correctement configuré pour afficher le composantuser-profilelorsqu'on navigue vers/user - Le fichier
app.routes.tsest correctement configuré pour afficher le composantuser-profilelorsqu'on navigue vers/ - La navigation entre les composants
sign-upetuser-profileest fonctionnelle
Ressources partagées sur cette quête
- Explications claires, en français, sur les routes en AngularJS, par Grafikart.https://www.youtube.com/watch?v=kFl1wrSZ4sQ&list=PLjwdMgw5TTLUDlJyx4yIPQjoI-w-7Zs1r&index=6