Routing et Navigation
avec Angular 18
Guide Complet
14/06/2024
Le Routing ou Routage permet
de gèrer les URL ou Routes
d'une Application Web .
Dans ce tutoriel nous allons
intégrer le routing en utilisant le
framework javascript Angular
version 18.0.2
Angular dispose de la librairie
angular@routeur.
Celle-ci nous permettra de mettre
en place rapidement et
facilement la navigation au
travers du routing.
ganatan.com
Comment le faire ?
Pour réaliser ce routage voici un résumé de ce que nous allons faire
Avant de Commencer
Qu'est-ce que le routing ou routage ?
Création de notre projet Angular
Nous utiliserons un projet existant contenant les fonctionnalités essentielles.
Le projet a été généré avec Angular CLI.
Structure du projet
Avant d'intégrer nos modifications il nous faut choisir une structure.
Initialisation du projet
En utilisant angular Cli
Child Routes
Comment gèrer des routes plus complexes
Effectuer les Tests
Réaliser les tests unitaires.
Code source
Pour les plus pressés d'entre vous, le code complet du projet est disponible
sur Github.
Il vous suffit de vous rendre à l'adresse suivante
https://github.com/ganatan/angular-react-routing
Avant de commencer
Tout d'abord un exemple pour essayer de comprendre la théorie.
2 films nous intéressent ou plutôt intéressent nos enfants (à vous de voir).
Utilisons donc Wikipedia c'est rapide et c'est simple.
Et voyons ce que cela donne en image.
Quelques explications maintenant.
Un site web est constitué d'une multitude de pages.
Ces pages sont écrites grâce notamment au langage HTML.
HTML signifie HyperText Markup Language.
L'hypertexte est la technologie qui permettra de relier une page à d'autres
pages via des hyperliens.
Le Routing est le mécanisme qui permet de naviguer d'une page à une autre
sur un site web.
Par exemple si vous tapez ces deux url dans votre navigateur.
https://fr.wikipedia.org/wiki/Le_Roi_lion
https://fr.wikipedia.org/wiki/Avengers:_Endgame
En fonction du nom de film indiqué dans l'url, l'application Web de Wikipedia va
déterminer le traitement à effectuer.
Ce traitement permettra d'afficher la page web correspondante au film demandé
(ici Le_Roi_lion ou Avengers:_Endgame).
C'est ce que l'on appelle le Routage ( traduit littéralement en anglais par
Routing ).
Si nous devions faire une comparaison c'est un peu comme un aiguilleur du
ciel ou un chef de gare.
Sans Routage on ne sait plus on va.
Donc vous l'aurez compris sans routage pas d'application Web.
Ce qui pourrait donner ça.
Ce principe de fonctionnement étant omniprésent dans l'utilisation d'un site web,
il nous faut l'appliquer au plus vite dans tout projet web.
Nous allons donc implémenter ce mécanisme dans notre projet Angular.
Création du projet Angular
Pour pouvoir continuer ce tutoriel nous devons bien évidemment disposer de
certains éléments
Node.js : La plateforme javascript
Git : Le logiciel de gestion de versions.
Angular CLI : L'outil fourni par Angular.
Visual Studio code : Un éditeur de code.
Vous pouvez consulter le tutoriel suivant qui vous explique en détails comment
faire
https://www.ganatan.com/tutorials/demarrer-avec-angular
Dans ce tutoriel nous allons utiliser un projet existant dont les caractéristiques
sont
Genéré avec Angular CLI
# Créez un répertoire demo (le nom est ici arbitraire)
mkdir demo
# Allez dans ce répertoire
cd demo
# Récupérez le code source sur votre poste de travail
git clone https://github.com/ganatan/angular-react-starter
# Allez dans le répertoire qui a été créé
cd angular-react-starter
cd angular
# Exécutez l'installation des dépendances (ou librairies)
npm install
# Exécutez le programme
npm run start
# Vérifiez son fonctionnement en lançant dans votre navigateur la
commande
http://localhost:4200/
Structure du projet
La question de la structure de notre projet se pose très rapidement.
Cette structure conditionnera les modifications que nous ferons au fur et à
mesure du développement du projet.
Lors de la création du projet avec Angular CLI la structure créée par défaut est la
suivante
Remarque
Le répertoire environments n'est plus généré automatiquement depuis Angular
15.
Je l'ai rajouté manuellement dans le tutoriel précédent Démarrer avec Angular.
|-- src/
|-- app
|-- assets
|-- environnement
package.json
Nous allons suivre cette façon de procéder en imaginant les éléments qui
pourraient constituer notre projet.
|-- src/
|-- app
|-- components
|-- directives
|-- mocks
|-- pages
|-- pipes
|-- services
|-- assets
|-- environnement
package.json
Le choix que nous avons fait est arbitraire, votre structure pourra prendre
n'importe quelle autre forme.
Ce choix sera néanmoins suivi dans les tutoriels suivants.
pages/general regroupera les éléments que l'on retrouve dans tous les
projets.
pages/application regroupera les éléments spécifiques à une
application.
Pour créer un nouveau projet il suffira de copier le projet de base et d'adapter
modules/application à nos besoins.
|-- app
|-- components
|-- directives
|-- mocks
|-- pages
|-- general (contient les éléments que l'on retrouve dans tous les types
de projet)
|-- not-found
|-- home
|-- contact
|-- login
|-- signup
|-- application (contient les éléments spécifiques à notre projet)
|-- item01
|-- item02
|-- ....
|-- itemXX
|-- pipes
|-- services
|-- assets
|-- environnement
Initialisation
Un rapide tour d'horizon avant de voir les détails techniques
Angular propose une librairie angular@routeur qui permet de gérer le routing.
Dans les versions Antérieures à Angular 17 le routing était gérée de la façon
suivante.
La librairie angular@routeur était importée dans un module dédié au routage.
Ce module portait le nom suivant app-routing.module.ts
Depuis la version 17 le routing est implicite lors de la création du projet
avec Angular CLI.
Le routing est ainsi géré via 3 fichiers de base.
app.component.ts
app.config.ts
app.routes.ts
Le schéma suivant vous expliquera comment il est géré avec la version 17.
Tout au long de ce didacticiel nous essaierons d'utiliser les commandes que
propose angular-cli pour genérer automatiquement le code source nécessaire.
Tout d'abord nous allons créer six composants qui seront utilisés dans le routing.
Un composant correspondra à une page Web.
Ce sont six pages Web classiques que l'on retrouve dans tout site web.
Home
Contact
About
Login
Signup
NotFound
Donc deux schémas pour récapituler ce que nous allons faire avec la version 17
et sa comparaison avec les version 16 et antérieures.
Routing avec Angular 17
Routing avec Angular 16
Nous utiliserons angular CLI pour cela.
Le tutoriel suivant vous donnera des informations sur les commandes Angular
CLI
https://www.ganatan.com/tutorials/demarrer-avec-angular-cli
Exécutons les commandes suivantes.
ng g correspond à la commande ng generate
# Création des nouveaux composants (méthode 1)
ng generate component pages/general/contact
ng generate component pages/general/login
ng generate component pages/general/signup
ng generate component pages/general/home
ng generate component pages/general/about
ng generate component pages/general/not-found
# Création des nouveaux composants (méthode 2)
ng g c pages/general/contact
ng g c pages/general/login
ng g c pages/general/signup
ng g c pages/general/home
ng g c pages/general/about
ng g c pages/general/not-found
Les répertoires pages et pages/general sont créés par la commande éxécutée.
Tous les fichiers relatifs à chaque composant sont créés automatiquement par
angular CLI.
Par exemple pour le composant Home 4 fichiers sont créés
home.component.css (code CSS dédié au design)
home.component.html (code HTML)
home.component.spec.ts (code de test unitaire du composant)
home.component.ts (partie logique en typescript de notre composant)
Il faut ensuite modifier les fichiers suivants
app-routes.ts
styles.css
app.component.html
app.component.css
app.component.ts
app.component.spec.ts
Ce qui permettra de traiter le routage désiré et les composants appelés.
src/app/app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './pages/general/home/home.component';
import { LoginComponent } from './pages/general/login/login.component';
import { SignupComponent } from './pages/general/signup/signup.component';
import { NotFoundComponent } from './pages/general/not-found/not-found.component';
import { AboutComponent } from './pages/general/about/about.component';
import { ContactComponent } from './pages/general/contact/contact.component';
export const routes: Routes = [
{ path: '', component: HomeComponent, },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '**', component: NotFoundComponent }
];
src/styles.css
body {
color: black;
font-weight: 400;
}
Dans le composant AppComponent nous prendrons soin de rajouter
l'élément <router-outlet> au niveau du fichier app.component.html.
Il indiquera au router ou afficher les éléments graphiques routés.
L'élément routerLink permettra de créer le lien vers les pages souhaitées.
src/app/app.component.html
<div class="app">
<header>
<section>
<h1>{{ title }}</h1>
</section>
<nav>
<h2>3 Links with Routes</h2>
<ul>
<li><a routerLink="/">Home</a></li>
<li><a routerLink="/login">Login</a></li>
<li><a routerLink="/signup">Signup</a></li>
</ul>
<h3>2 Links with Child Routes</h3>
<ul>
<li><a routerLink="/about">About</a></li>
<li><a routerLink="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
<h4>Routes Result</h4>
<router-outlet></router-outlet>
</main>
<footer>
<a href="{{ footerUrl }}">{{ footerLink }}</a>
</footer>
</div>
src/app/app.component.css
h1 {
color: blue;
}
.app {
font-family: Arial, Helvetica, sans-serif;
max-width: 500px;
margin: auto;
}
# Création du routing (méthode 1)
ng generate module app-routing --flat --module=app
# Création du routing (méthode 2)
ng g m app-routing --flat --module=app
Il faut ensuite modifier les fichiers suivants
app-routing.module.ts
styles.css
app.component.html
app.component.css
app.component.ts
app.component.spec.ts
app.e2e-spec.ts
app.po.ts
Ce qui permettra de traiter le routage désiré et les composants appelés.
Dans le fichier app-routing.module.ts
Importer les modules Routes et RouterModule
Configurer les Routes
Appeler la méthode forRoot de RouterModule
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './modules/general/about/about.component';
import { ContactComponent } from
'./modules/general/contact/contact.component';
import { HomeComponent } from './modules/general/home/home.component';
import { LoginComponent } from './modules/general/login/login.component';
import { SignupComponent } from
'./modules/general/signup/signup.component';
import { NotFoundComponent } from './modules/general/not-found/not-
found.component';
const routes: Routes = [
{ path: '', component: HomeComponent, },
{ path: 'contact', component: ContactComponent },
{ path: 'about', component: AboutComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: '**', component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
declarations: []
})
export class AppRoutingModule { }
src/styles.css
body {
color: black;
font-weight: 400;
}
Dans le composant AppComponent nous prendrons soin de rajouter l'élément
<router-outlet> au niveau du fichier app.component.html.
Il indiquera au router ou afficher les éléments graphiques routés.
L'élément routerLink permettra de créer le lien vers les pages souhaitées.
src/app/app.component.html
<div class="app">
<header>
<section>
<h1>{{ title }}</h1>
<h2> {{ version }}</h2>
</section>
<nav>
<ul>
<li><a routerLink="/">Home</a></li>
<li><a routerLink="/about">About</a></li>
<li><a routerLink="/contact">Contact</a></li>
<li><a routerLink="/login">Login</a></li>
<li><a routerLink="/signup">Signup</a></li>
</ul>
</nav>
</header>
<main>
<router-outlet></router-outlet>
</main>
<footer>
<a href="https://www.ganatan.com/">www.ganatan.com</a>
</footer>
</div>
src/app.component.css
h1 {
color: blue;
}
.app {
font-family: Arial, Helvetica, sans-serif;
max-width: 500px;
margin: auto;
src/app.component.ts
}
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'angular-routing;
footerUrl = 'https://www.ganatan.com';
footerLink = 'www.ganatan.com';
}
Le Routing fonctionne
Après toutes ces modifications vérifions que cela fonctionne.
On éxécute le script de lancement et on teste le résultat dans le navigateur.
# Exécutez l'application
npm run start
# Testez l'application dans votre navigateur
http://localhost:4200
Le programme fonctionne , testez le routing en cliquant sur les différents liens.
On est d'accord ce n'est pas très joli.
Mais on a fait rapide on a utilisé du HTML et du CSS très simples.
On peaufinera tout ça plus tard en utilisant Bootstrap dans un tutoriel suivant.
En attendant le résultat en image.
Il nous faut rajouter le module RouterTestingModule au niveau des tests
unitaires du composant App.
Ce rajout se fait au niveau du fichier de test correspondant
app.component.spec.ts.
src/app/app.component.spec.ts
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { RouterTestingModule } from '@angular/router/testing';
describe('AppComponent', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [AppComponent]
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'angular-routing'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('angular-routing');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('angular-
routing');
});
});
Child Routes
Pour gérer des routes plus complexes, par exemple faire du routage à partir
du composant contact, il nous faut aborder la gestion des Child routes.
Cette question est évoquée dans la documentation
https://angular.io/guide/router#child-route-configuration
Nous allons rajouter trois composants qui seront accessibles à partir du
composant Contact
mailing
mapping
website
# Rajout des trois composants
ng generate component modules/general/contact/mailing --module=app
ng generate component modules/general/contact/mapping --module=app
ng generate component modules/general/contact/website --module=app
4 fichiers sont automatiquement créés pour chaque composant par exemple
pour mailing
mailing.component.css
mailing.component.html
mailing.component.spec.ts
mailing.component.ts
Il nous reste à modifier le routage
contact.component.html
contact.component.spec.ts
app-routing.module.ts
contact.component.html
<div>
<p>contact works!</p>
<ul>
<li><a routerLink="/contact/mailing">Mailing</a></li>
<li><a routerLink="/contact/mapping">Mapping</a></li>
<li><a routerLink="/contact/website">Website</a></li>
</ul>
<h4>Child Routes Result</h4>
<router-outlet></router-outlet>
</div>
app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-
found.component';
import { AboutComponent } from './modules/general/about/about.component';
import { LoginComponent } from './modules/general/login/login.component';
import { SignupComponent } from './modules/general/signup/signup.component';
import { ContactComponent } from './modules/general/contact/contact.component';
import { MailingComponent } from
'./modules/general/contact/mailing/mailing.component';
import { MappingComponent } from
'./modules/general/contact/mapping/mapping.component';
import { WebsiteComponent } from
'./modules/general/contact/website/website.component';
const routes: Routes = [
{ path: '', component: HomeComponent, },
{ path: 'about', component: AboutComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{
path: 'contact', component: ContactComponent,
children: [
{ path: '', component: MailingComponent },
{ path: 'mailing', component: MailingComponent },
{ path: 'mapping', component: MappingComponent },
{ path: 'website', component: WebsiteComponent },
],
},
{ path: '**', component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
declarations: []
})
export class AppRoutingModule { }
contact.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ContactComponent } from './contact.component';
describe('ContactComponent', () => {
let component: ContactComponent;
let fixture: ComponentFixture<ContactComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [ContactComponent]
});
fixture = TestBed.createComponent(ContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Tests
Il ne reste plus qu'à tester les scripts suivants.
# Développement
npm run start
http://localhost:4200/
# Test de la page not-found
http://localhost:4200/lien-inconnu
# Tests
npm run test
# Production
npm run build
Code source
Le code source utilisé en début de tutoriel est disponible sur github
https://github.com/ganatan/angular-react-starter
Le code source obtenu à la fin de ce tutoriel est disponible sur github
https://github.com/ganatan/angular-react-routing
Les étapes suivantes vous permettront d'obtenir une application prototype
Etape 3 : Lazy loading avec Angular
Etape 4 : Bootstrap avec Angular
Etape 5 : Modules avec Angular
Etape 6 : Server Side Rendering avec angular
Etape 7 : Progressive Web App avec Angular
Etape 8 : Search Engine Optimization avec Angular
Etape 9 : HttpClient avec Angular
Les étapes suivantes vous permettront d’améliorer ce prototype
Components avec Angular
Services avec Angular
Template Driven Forms avec Angular
Charts avec Angular
La dernière étape permet d'obtenir un exemple d'application
Créer une application Web complète avec Angular