*** lundi, 20 avril 2026 --> semaine 12 !!! ***
Semaine 9 - Les Services et le Routing
Télécharger : 5 - Théorie Semaine 9 (Structure du code avec les Services).docx
*ngIf sera bientôt déprécié "Depreciated"
Remplacer le vieux code dans le à marques-voitures.html par : (@if)
<!-- <div style="width:20px;height:20px;background-color:red;"
*ngIf="voituresStatus === 'Non disponible'"></div> -->
@if (voituresStatus === 'Non disponible') {
<div style="width:20px;height:20px;background-color:red;"></div>
} @else if (voituresStatus === 'Disponible') {
<div style="width:20px;height:20px;background-color:green;"></div>
} @else {
<!-- Rien du tout -->
}
*ngFor sera bientôt déprécié "Depreciated"
Remplacer le vieux code dans le à app.html par : (@for)
<!--<app-marques-voitures *ngFor="let totovoiture of voitures"
[voituresName]="totovoiture.name"
[voituresStatus]="totovoiture.status"></app-marques-voitures> -->
@for (item of voitures; track item.name) {
<app-marques-voitures
[voituresName] = item.name
[voituresStatus] = item.status >
</app-marques-voitures> }
5 - Améliorez la structure du code avec les Services
Partie 5 (Voitures9)
1. Les Services
Dit très simplement, un service permet de centraliser des parties de votre code et des données qui sont utilisées par plusieurs parties de votre application ou de manière globale par l'application entière. Les services permettent donc :
· de ne pas avoir le même code doublé ou triplé à différents niveaux de l'application - ça facilite donc la maintenance, la lisibilité et la stabilité du code ;
· de ne pas copier inutilement des données - si tout est centralisé, chaque partie de l'application aura accès aux mêmes informations, évitant beaucoup d'erreurs potentielles.
Dans le cas de l'application que vous avez créée lors des derniers chapitres, on pourrait imaginer un service VoitureService qui contiendrait les données des voitures, et également des fonctions globales liées aux voitures, comme tout rendre Disponible ou Non disponible que vous pourrez enfin intégrer. L'authentification reste simulée pour l'instant, mais quand vous l'intégrerez, on pourrait imaginer un deuxième service AuthService qui s'occuperait de vérifier l'authentification de l'utilisateur, et qui pourrait également stocker des informations sur l'utilisateur actif comme son adresse mail et son pseudo.
Pour être utilisé dans l'application, un service doit être injecté, et le niveau choisi pour l'injection est très important. Il y a trois niveaux possibles pour cette injection :
· Dans AppModule : ainsi, la même instance du service sera utilisée par tous les components de l'application et par les autres services ;
· Dans App : comme ci-dessus, tous les components auront accès à la même instance du service mais non les autres services ;Component
· Dans un autre component : le component lui-même et tous ses enfants (c'est-à-dire tous les components qu'il englobe) auront accès à la même instance du service, mais le reste de l'application n'y aura pas accès.
Pour les exemples de ce cours, vous injecterez systématiquement les services dans AppAppModuleComponent pour rendre disponible une seule instance par service à toutes les autres parties de votre application.
Vous y intégrerez bientôt des données et des fonctions, mais pour l'instant, vous allez injecter ce service dans App en l'ajoutant au constructor et n'oubliez pas d'ajouter l'import correspondant en haut du fichier :Component
…
import { ServiceVoiture } from './services/service-voiture';
@Component({
selector: 'app-root',
imports: [MonPremier,MarquesVoitures,CommonModule],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App {
title = 'Voitures8 de Mers 2026';
isAuth = false;
lastUpdate = new Observable((observer) => {
//setTimeout(() => observer.next(new Date().toString()), 1000);
//if (typeof window !== 'undefined') {
// window.setInterval(()=>{observer.next(new Date().toString())},1000);
//}
if (typeof window !== 'undefined') {
window.setInterval(()=>{observer.next(new Date().toLocaleString("fr-CA"))},1000);
}
});
voitures = [
{
name: 'Bugatti',
status: 'Non disponible'
},
{
name: 'Ferrari',
status: 'Disponible'
},
{
name: 'Lambhorgini',
status: 'Non disponible'
}
];
constructor(private cdr: ChangeDetectorRef, private service:ServiceVoiture) {
setTimeout(
() => {
this.isAuth = true;
this.cdr.detectChanges();
}, 4000
);
}
…
Angular crée maintenant une instance du service ServiceVoiture. Pour l'intégrer dans un component, on le déclare comme argument dans son constructeur. Vous pouvez l'intégrez-le dans un de vos autres component (sans oublier d'ajouter l'import en haut):
Exemple pour Moi = mon-premier2.component.ts
Maintenant, dans App ou plus tard, dans votre component ( moi = mon-premier2.component.ts), vous avez un membre appelé ComponentVoitureService qui correspond à l'instance de ce service que vous avez créé dans App . Vous y ajouterez de la fonctionnalité dans le chapitre suivant.Component
Utilisez les Services
Le premier élément qu'il serait logique de déporter dans le service serait l'array Voitures. Copiez-le depuis App , collez-le dans ComponentVoitureService et, de nouveau dans App , déclarez Componentvoitures simplement comme un array de type any :
Dans service-voiture.service.ts:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ServiceVoiture {
voitures = [
{
name: 'Bugatti',
status: 'Non disponible'
},
{
name: 'Ferrari',
status: 'Disponible'
},
{
name: 'Lambhorgini',
status: 'Non disponible'
}
];
constructor() { }
}
Dans app.component.ts : ( remplacer le Tableau par à )
export class App {
title = 'Voitures9 de Mers 2026';
isAuth = false;
lastUpdate = new Observable((observer) => {
//setTimeout(() => observer.next(new Date().toString()), 1000);
//if (typeof window !== 'undefined') {
// window.setInterval(()=>{observer.next(new Date().toString())},1000);
//}
if (typeof window !== 'undefined') {
window.setInterval(()=>{observer.next(new Date().toLocaleString("fr-CA"))},1000);
}
});
voitures : any;
Il faut maintenant que App puisse récupérer les informations stockées dans ComponentVoitureService . Pour cela, vous allez implémenter la méthode ngOnInit() .
ngOnInit() correspond à une "lifecycle hook". Le détail de ces hooks va au-delà du cadre de ce cours, mais pour l'instant, tout ce que vous avez besoin de savoir, c'est que la méthode ngOnInit() d'un component est exécutée une fois par instance au moment de la création du component par Angular, et après son constructeur. On l'utilise très souvent pour initialiser des données une fois le component créé. Plus tard dans cette partie du cours, vous découvrirez également ngOnDestroy() . Pour plus d'informations, référez-vous à la documentation d'Angular.
Pour ce faire, vous allez d'abord créer la fonction ngOnInit() - généralement on la place après le constructeur et avant les autres méthodes du component : (si elle n'est pas déjà présente !!!)
Dans app.component.ts :
voitures : any;
constructor(private cdr: ChangeDetectorRef, private service:ServiceVoiture) {
setTimeout(
() => {
this.isAuth = true;
this.cdr.detectChanges();
}, 4000
);
}
ngOnInit() {
}
onAllumer() {
console.log('On rend tout disponible !');
}
}
Ensuite, dans la déclaration de classe App , vous allez implémenter l'interface ComponentOnInit (en l'important depuis @angular/core en haut) :
import { Component, OnInit} from '@angular/core';
import { MonPremier } from './mon-premier/mon-premier';
import { MarquesVoitures } from './marques-voitures/marques-voitures';
import { ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable } from 'rxjs';
import { ServiceVoiture } from './services/service-voiture';
@Component({
selector: 'app-root',
imports: [MonPremier,MarquesVoitures,CommonModule],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App implements OnInit{
title = 'Voitures9 de Mers 2026';
isAuth = false;
…
Vous pouvez maintenant récupérer les informations depuis VoitureService dans la méthode ngOnInit() de app.ts :
constructor(private cdr: ChangeDetectorRef, private service:ServiceVoiture) {
setTimeout(
() => {
this.isAuth = true;
this.cdr.detectChanges();
}, 4000
);
}
ngOnInit() {
this.voitures = this.service.voitures;
}
La liaison directe à un array comme ici n'est généralement pas la meilleure des pratiques. J'ai choisi d'employer cette méthode ici pour montrer plus simplement l'intégration des services, mais ne vous en faites pas : nous verrons les meilleures méthodes plus tard dans ce cours .
Votre application devrait fonctionner à nouveau, avec la liste des voitures qui s'affiche comme avant. Il n'y a aucune différence visuelle, mais votre code est maintenant plus modulaire, et ce sera plus facile d'ajouter des fonctionnalités. Par exemple, vous allez pouvoir créer deux nouvelles méthodes : switchOnAll() et switchOffAll() pour rendre Disponible ou Non disponible tous les voitures d'un coup.
Commencez par préparer ces méthodes dans service-voiture.service.ts:
constructor() { }
switchOnAll() {
for(let voiture of this.voitures) {
voiture.status = 'Disponible';
}
}
switchOffAll() {
for(let voiture of this.voitures) {
voiture.status = 'Non disponible';
}
}
}
Puis ajoutez un deuxième bouton dans le template(.html) de AppComponent :
(Le deuxième bouton devrait déjà être ajouter depuis la dernière partie du TP4 !!!)
Enfin, il ne vous reste plus qu'à capturer les événements click dans App pour ensuite déclencher les méthodes dans ServiceComponentVoiture . Commencez déjà par ServiceonAllumer() AJOUTER dans app.component.ts:
onAllumer() {
if(confirm('Etes-vous sûr de vouloir rendre tous vos voitures Disponible ?')) {
this.service.switchOnAll();
} else {
return;
}
}
Ensuite, pour onFermer() , vous allez d'abord afficher un message de confirmation pour vous assurer que l'utilisateur est certain de vouloir rendre tout Non disponible :
onFermer() {
if(confirm('Etes-vous sûr de vouloir rendre tous vos voitures Non disponible ?')) {
this.service.switchOffAll(); } else {
return;
}
}
Vos boutons rendent Disponible ou Non disponible tous les voitures grâce à la communication entre votre App et votre ServiceComponentVoiture .Service
Mais j'aurais pu faire tout ça à l'intérieur du component - quel est l'intérêt d'avoir tout mis dans un service ?
Effectivement, les fonctionnalités que vous avez ajoutées pour l'instant auraient pu rester dans App , mais dans le chapitre suivant, vous allez profiter du service pour créer de la communication entre vos components, notamment des components enfants vers leur parent.Component
2. Faites communiquer vos components
Pour l'instant, votre utilisateur ne peut que rendre Disponible ou Non disponible tous les voitures à la fois. Ce qui pourrait être très intéressant, ce serait qu'il puisse en rendre Disponible ou Non disponible un à la fois. Actuellement, le plan de l'application ressemble à ça :
ServiceVoiture fournit les données sur les Servicevoitures à App . Ensuite, ComponentApp génère trois instances de ComponentVoiture selon ces données. Il n'y a actuellement aucune communication entre les components enfants et leur parent. Vous pouvez modifier cela en intégrant ServiceComponentVoiture dans les ServiceVoitureComponent et en créant des méthodes qui permettent de modifier une voiture à la fois. Procédez étape par étape.
Dans un premier temps, il faudra que chaque instancede Voiture puisse dire à ServiceComponentVoiture à quel membre de l'array Servicevoitures elle correspond. Heureusement, Angular nous permet de faire ça facilement. Dans la directive *ngFor, maintenant @for, ajoutez dans app.component.html :
@for (item of voitures; track item.name; let i = $index) {
<app-marques-voitures
[voituresName] = item.name
[voituresStatus] = item.status >
</app-marques-voitures> }
Cette commande rend disponible l'index de l'objet voiture dans l'array voitures. Ensuite, il faut pouvoir capturer et travailler avec cette variable : vous pouvez utiliser le property binding. Pour cela, ajoutez un membre index au component en tant export
Dans marques-voitures.component.ts :
…
export class MarquesVoitures implements OnInit{
@Input() voituresName: string = 'Bugatti';
@Input() voituresStatus: string = 'Non disponible';
@Input() indexdesVoiture: number = 5;
constructor() { }
…
Puis liez-y l'index i depuis le template (app.component.html) :
À partir de là, vous avez une variable index disponible à l'intérieur du component qui correspond à l'index de la voiture dans l'array de VoitureService. Vous verrez dans quelques instants pourquoi vous en avez besoin.
Dans VoitureService , vous allez maintenant créer les méthodes permettant de rendre Disponible ou Non disponible une seul voiture en fonction de son index dans l'array voitures , service-voiture.service.ts:
AJOUTER à
switchOnOne(index: number) {
this.voitures[index].status = 'Disponible';
}
switchOffOne(index: number) {
this.voitures[index].status = 'Non disponible';
}
Ensuite, dans MarqueVoiture , vous allez d'abord intégrer le service ServiceComponentVoiture, en l'important en haut du fichier comme toujours dans marques-voitures.Servicecomponent.ts:
Puis vous allez préparer la méthode qui, en fonction du statut actuel de l'appareil, le rendra Disponible ou Non disponible:
import { Component, Input, OnInit } from '@angular/core';
import { FormsModule} from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ServiceVoiture} from '../services/service-voiture';
@Component({
selector: 'app-marques-voitures',
imports: [FormsModule,CommonModule],
templateUrl: './marques-voitures.html',
styleUrl: './marques-voitures.scss',
})
export class MarquesVoitures implements OnInit{
@Input() voituresName: string = 'Bugatti';
@Input() voituresStatus: string = 'Non disponible';
@Input() indexdesVoiture: number = 5;
constructor(private service:ServiceVoiture) { }
ngOnInit(): void {
}
getStatus() {
return this.voituresStatus;
}
getColor() {
if(this.voituresStatus === 'Non disponible'){
return 'red';
}
else if(this.voituresStatus === 'Disponible'){
return 'green';
}
else {return 'black'}
}
onSwitchOn() {
this.service.switchOnOne(this.indexdesVoiture);
}
onSwitchOff() {
this.service.switchOffOne(this.indexdesVoiture);
}
}
Le nom onSwitch() ici est choisi pour respecter la norme d'employer "on" pour la capture d'un événement, et non pour dire "switch on" comme "Disponible".
Enfin, vous allez créer le bouton dans le template qui déclenchera cette méthode. Il serait intéressant que ce bouton soit contextuel : si la voiture est Disponible, il affichera "Non disponible" et inversement. Pour cela, le plus simple est de créer deux boutons dotés de la directive *ngIf dans marques-voitures.component.html :
<h4 [ngStyle]="{color: getColor()}">Voiture : {{ voituresName }} -- Statut : {{ getStatus() }}</h4>
<a [routerLink]=[id]>Détail</a>
<input type="text" class="form-control" [(ngModel)]="voituresName">
<input type="text" class="form-control" [(ngModel)]="voituresStatus">
@if (voituresStatus === 'Non disponible') {
<button class="btn btn-sm btn-success" (click)="onSwitchOn()">Disponible</button>
}
@if (voituresStatus === 'Disponible') {
<button class="btn btn-sm btn-danger" (click)="onSwitchOff()">Non disponible</button>
}
</li>
Vous pouvez supprimer la <div> conditionnelle rouge, car elle ne sert plus vraiment, avec tous les styles que vous avez ajoutés pour signaler l'état d'une voiture ou non!
VoitureService ,il y ait des appels API permettant de vraiment rendre Disponible ou Non disponible les voitures et d'en vérifier le fonctionnement.
Réf. : https://www.itsolutionstuff.com/post/how-to-create-service-in-angular-17example.html
Télécharger : 6 - Théorie Semaine 9 (Gérez la navigation avec le Routing).docx
6 - Gérez la navigation avec le Routing
Partie 6 (Voitures10)
1. Gérez la navigation avec le Routing
L'un des énormes avantages d'utiliser Angular est de pouvoir créer des "single page application" (SPA). Sur le Web, ces applications sont rapides et lisses : il n'y a qu'un seul chargement de page au début, et même si les données mettent parfois du temps à arriver, la sensation pour l'utilisateur est celle d'une application native. Au lieu de charger une nouvelle page à chaque clic ou à chaque changement d'URL, on remplace le contenu ou une partie du contenu de la page : on modifie les components qui y sont affichés, ou le contenu de ces components. On accomplit tout cela avec le "routing", où l'application lit le contenu de l'URL pour afficher le ou les components requis.
L'application des voitures n'a que la view des voitures à afficher pour le moment ; je vous propose de créer un component pour l'authentification (qui restera simulée pour l'instant) et vous créerez un menu permettant de naviguer entre les views.
Tout d'abord, créez le component avec le CLI :
sudo ng g c auth
Vous allez également devoir modifier un peu l'organisation actuelle afin d'intégrer plus facilement le routing : vous allez créer un component qui contiendra toute la view actuelle et qui s'appellera VoitureView :Component
sudo ng g c voiture-view
Ensuite, coupez tout le contenu de la colonne de app., enregistrez-le dans voiturecomponent.html-view.component.html
, et remplacez-le par la nouvelle balise <app-voiture-view> dans app. :component.html
<div style="text-align:center">
<h1>
Bienvenue aux {{ title }}!
</h1>
</div>
<app-mon-premier></app-mon-premier>
Il faudra également déménager la logique de cette view (app.component.ts) pour que tout fonctionne à nouveau : injectez ServiceVoitureService "mettre les bons import dans le haut du fichier" (et , transférer l'array voitures , isAuth, lastUpdate, intégrez la logique ngOnInit et déplacez les fonctions onAllumer() et onFermer() dans voiture-view.component.ts :
Mon résultat:
import { Component, OnInit } from '@angular/core';
import { ServiceVoiture } from '../services/service-voiture';
import { MarquesVoitures } from '../marques-voitures/marques-voitures';
import { ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable } from 'rxjs';
@Component({
selector: 'app-voiture-view',
imports: [MarquesVoitures, CommonModule],
templateUrl: './voiture-view.html',
styleUrl: './voiture-view.scss',
})
export class VoitureView implements OnInit{
isAuth = false;
voitures : any;
lastUpdate = new Observable((observer) => {
//setTimeout(() => observer.next(new Date().toString()), 1000);
//if (typeof window !== 'undefined') {
// window.setInterval(()=>{observer.next(new Date().toString())},1000);
//}
if (typeof window !== 'undefined') {
window.setInterval(()=>{observer.next(new Date().toLocaleString("fr-CA"))},1000);
}
});
constructor(private cdr: ChangeDetectorRef, private service:ServiceVoiture) {
setTimeout(
() => {
this.isAuth = true;
this.cdr.detectChanges();
}, 4000
);
}
ngOnInit() {
this.voitures = this.service.voitures;
}
onAllumer() {
if(confirm('Etes-vous sûr de vouloir rendre tous vos voitures Disponible ?')) {
this.service.switchOnAll();
} else {
return;
}
}
onFermer() {
if(confirm('Etes-vous sûr de vouloir rendre tous vos voitures Non disponible ?')) {
this.service.switchOffAll(); } else {
return;
}
}
}
Vous pouvez faire le ménage dans App , en retirant tout ce qui n'y sert plus. Assurez-vous d'avoir également une boolean ComponentisAuth dans VoitureView , et déclarez-la comme Componentfalse , car vous allez intégrer un service d'authentification pour la suite.
Après le ménage, voici le contenue de mon AppComponent (app.component.ts):
import { Component} from '@angular/core';
import { VoitureView } from './voiture-view/voiture-view';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
imports: [CommonModule,VoitureView],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App {
title = 'Voitures10 de rêve de Mers 2026';
}
*** Notez que j'ai également enlever ce qui avait rapport avec "mon-premier" car je ne vais plus l'utiliser avant quelques semaines.
Ajoutez la barre de navigation suivante à AppComponent (.html) :
…
<div style="text-align:center">
<h1>
Bienvenue aux {{ title }}!
</h1>
</div>
<HR>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="active"><a href="#">Voitures</a></li>
<li>
<a href="#">>Authentification</a>
</li>
</ul>
</div>
</nav>
<HR>
<div class="container">
<div class="row">
<div class="col-xs-12">
<app-voiture-view></app-voiture-view>
</div>
</div>
</div>
…
Maintenant, tout est prêt pour créer le routing de l'application.
Tout d'abord, qu'est-ce qu'une route dans une application Angular ?
Il s'agit des instructions d'affichage à suivre pour chaque URL, c'est-à-dire quel(s) component(s) il faut afficher à quel(s) endroit(s) pour un URL donné.
Puisque le routing d'une application est fondamentale pour son fonctionnement, on déclare les routes dans app.routes.ts
Il est possible d'avoir un fichier séparé pour le routing, mais en termes de fonctionnalité, cela ne change rien : c'est juste une question d'organisation du code.
On crée une constante de type Routes (qu'on importe depuis @angular/router ) qui est un array d'objets JS qui prennent une certaine forme :
import { Routes } from '@angular/router';
import { Auth } from './auth/auth';
import { VoitureView } from './voiture-view/voiture-view';
Les routes sont maintenant créées, mais il faut les enregistrer dans votre application. Pour cela, vous allez importer RouterModule depuis @angular/router et vous allez l'ajouter à l'array imports de votre AppComponent, tout en lui appelant la méthode forRoot() en lui passant l'array de routes que vous venez de créer :
import { Routes, RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { VoitureViewComponent } from './voiture-view/voiture-view.component'
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, MonPremierComponent, MonPremier2Component, CommonModule, VoitureViewComponent, RouterModule],
Maintenant que les routes sont enregistrées, il ne reste plus qu'à dire à Angular où vous souhaitez afficher les components dans le template (app.component.html) lorsque l'utilisateur navigue vers la route en question. On utilise la balise <router-outlet> :
<HR>
<div class="container">
<div class="row">
<div class="col-xs-12">
<router-outlet></router-outlet>
</div>
</div>
</div>
<!-- <app-voiture-view></app-voiture-view> -->
<app-coordonee></app-coordonee>
<app-pied></app-pied>
Lorsque vous changez de route (pour l'instant, en modifiant l'URL directement dans la barre d'adresse du navigateur), la page n'est pas rechargée, mais le contenu sous la barre de navigation change. Dans le chapitre suivant, vous allez intégrer les liens de la barre de navigation afin que l'utilisateur puisse naviguer facilement.
3. Naviguez avec les routerLink
Afin que l'utilisateur puisse naviguer à l'intérieur de votre application, il est nécessaire de créer des liens ou des boutons qui naviguent vers les routes que vous avez créées. Dans le chapitre précédent, vous avez créé des liens typiques dans la barre de navigation, mais qui ne font rien pour l'instant.
Vous pourriez vous dire qu'il suffirait de marquer le path de vos routes directement dans l'attribut href , et techniquement, cela permet d'atteindre les routes que vous avez créées.
Alors pourquoi on ne fait pas comme ça ?
Tout simplement parce que, si vous regardez bien, en employant cette technique, la page est rechargée à chaque clic !
On perd totalement l'intérêt d'une Single Page App !
Du coup, on retire l'attribut href et on le remplace par l'attribut routerLink :
Dans app.component.html à
<HR>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" routerLinkActive="active" routerLink="voitures">Voitures</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" routerLink="auth">Authentification</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" routerLinkActive="active" href="#">Disabled</a>
</li>
</ul>
</div>
</nav>
<HR>
Ainsi, les routes sont chargées instantanément : on conserve l'ergonomie d'une SPA.
Pour finaliser cette étape, il serait intéressant que la classe active ne s'applique qu'au lien du component réellement actif. Heureusement, Angular fournit un attribut pour cela qui peut être ajouté au lien directement ou à son élément parent :
Maintenant, les liens s'activent visuellement.
4. Naviguez avec le Router
Il peut y avoir des cas où vous aurez besoin d'exécuter du code avant une navigation. Par exemple, on peut avoir besoin d'authentifier un utilisateur et, si l'authentification fonctionne, de naviguer vers la page que l'utilisateur souhaite voir. Je vous propose d'intégrer cette fonctionnalité à l'application des voitures électriques (l'authentification elle-même restera simulée pour l'instant).
Tout d'abord, créez un nouveau fichier service-authauth.service.ts.service.ts dans le dossier services pour gérer l'authentification (n'oubliez pas de l'ajouter également dans dans AppComponent ) :
Créer un Service appelé "service-auth" dans mon cas:
ng generate service service-auth
Copier le nouveaux fichier dans le dossier service.
Ensuite, dans app.component.ts :
import { ServiceAuth } from './services/service-auth'
et
export class App {
title = 'Voitures10 de rêve de Mers 2026';
constructor(private service: ServiceAuth){
}
}
Dans service-auth.service.ts:
export class ServiceAuth {
isAuth = false;
signIn() {
return new Promise(
(resolve, reject) => {
setTimeout(
() => {
this.isAuth = true;
resolve(true);
}, 2000
);
}
);
}
signOut() {
this.isAuth = false;
}
constructor() { }
}
Suggestion si la route ne fonctionne pas bien, redémarrer avec sudo ng serve et redémarrer VS Code. Solution ultime, recréer le fichier auth.service.ts
La variable isAuth donne l'état d'authentification de l'utilisateur. La méthode signOut() "déconnecte" l'utilisateur, et la méthode signIn() authentifie automatiquement l'utilisateur au bout de 2 secondes, simulant le délai de communication avec un serveur.
Dans le component auth.component.ts, vous allez simplement créer deux boutons et les méthodes correspondantes pour se connecter et se déconnecter (qui s'afficheront de manière contextuelle : le bouton "se connecter" ne s'affichera que si l'utilisateur est déconnecté et vice versa) :
import { Component } from '@angular/core';
import { ServiceAuth } from '../services/service-auth';
@Component({
selector: 'app-auth',
imports: [],
templateUrl: './auth.html',
styleUrl: './auth.scss',
})
export class Auth {
authStatus: boolean = true;
constructor(private service : ServiceAuth) { }
ngOnInit() {
this.authStatus = this.service.isAuth;
}
onSignIn() {
this.service.signIn().then(
() => {
console.log('Sign in successful!');
this.authStatus = this.service.isAuth;
}
);
}
onSignOut() {
this.service.signOut();
this.authStatus = this.service.isAuth;
}
}
Puisque la méthode signIn() du service retourne une Promise, on peut employer une fonction callback asynchrone avec .then() pour exécuter du code une fois la Promise résolue. Ajoutez simplement les boutons, et tout sera prêt pour intégrer la navigation :
Dans auth.component.html
<h2>Authentification</h2>
@if (!authStatus) {
<button class="btn btn-success" (click)="onSignIn()">Se connecter</button>
}
@if (authStatus) {
<button class="btn btn-danger" (click)="onSignOut()">Se déconnecter</button>
}
*** Ajouter le module nécessaire pour utiliser *ngIf dans le fichier auth.ts correspondant:
import { CommonModule } from '@angular/common';
et plus bas …
imports: [CommonModule],
Le comportement recherché serait qu'une fois l'utilisateur authentifié, l'application navigue automatiquement vers la view des voitures. Pour cela, il faut injecter le Router (importé depuis @angular/router ) pour accéder à la méthode navigate() :
Dans auth.component.ts :
import { Component } from '@angular/core';
import { ServiceAuth } from '../services/service-auth';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
@Component({
selector: 'app-auth',
imports: [CommonModule],
templateUrl: './auth.html',
styleUrl: './auth.scss',
})
export class Auth {
authStatus: boolean = true;
constructor(private service : ServiceAuth, private router: Router) { }
ngOnInit() {
this.authStatus = this.service.isAuth;
}
onSignIn() {
this.service.signIn().then(
() => {
console.log('Sign in successful!');
this.authStatus = this.service.isAuth;
this.router.navigate(['voitures']);
}
);
}
onSignOut() {
this.service.signOut();
this.authStatus = this.service.isAuth;
}
}
La fonction navigate prend comme argument un array(tableau) d'éléments (ce qui permet de créer des chemins à partir de variables, par exemple) qui, dans ce cas, n'a qu'un seul membre : le chemin "path" souhaité.
s est toujours accessible actuellement, même sans authentification : dans un chapitre ultérieur, vous apprendrez à le sécuriser totalement. Avant cela, vous allez apprendre à ajouter des paramètres à vos routes.
5. Paramètres des Routes
Imaginez qu'on souhaite pouvoir cliquer sur un voiture dans la liste de voitures afin d'afficher une page avec plus d'informations sur cette voiture : on peut imaginer un système de routing de type voitures/nom-de-la voiture, par exemple. Si on n'avait que deux ou trois voitures, on pourrait être tenté de créer une route par voiture, mais imaginez un cas de figure où l'on aurait 30 voitures, ou 300. Imaginez qu'on laisse l'utilisateur créer de nouvelles voitures ; l'approche de créer une route par voiture n'est pas adaptée. Dans ce genre de cas, on choisira plutôt de créer une route avec paramètre.
Tout d'abord, vous allez créer la route dans app.routes.ts:
const appRoutes: Routes = [
{ path: 'voitures',component: VoitureView },
{ path: 'voitures/:id', component: SingleVoitureComponent},
{ path: 'auth', component: Auth },
{ path: '', component: VoitureView },
];
L'utilisation des deux-points : avant un fragment de route déclare ce fragment comme étant un paramètre : tous les chemins de type voitures/* seront renvoyés vers SingleVoiture, que vous allez maintenant créer :Component
sudo ng g c single-voiture
dans single-voiture.component.ts :
import { Component } from '@angular/core';
import { ServiceVoiture } from '../services/service-voiture';
import { RouterModule } from '@angular/router';
@Component({
selector: 'app-single-voiture',
imports: [RouterModule],
templateUrl: './single-voiture.html',
styleUrl: './single-voiture.scss',
})
export class SingleVoiture {
name: string = 'Voiture';
status: string = 'Statut';
constructor(private service:ServiceVoiture) { }
}
dans single-voiture.component.html :
<h2>{{ name }}</h2>
<p>Statut : {{ status }}</p>
<a routerLink="/voitures">Retour à la liste</a>
Ajouter dans app.routes.ts:
import { SingleVoiture } from './single-voiture/single-voiture';
/voitures/nom, peu importe le nom que vous choisissez, vous avez accès à SingleVoitureComponent .
Maintenant, vous allez y injecter ActivatedRoute , importé depuis @angular/router , afin de récupérer le fragment id de l'URL dans single-voiture.component.ts :
import { Component } from '@angular/core';
import { ServiceVoiture } from '../services/service-voiture';
import { RouterModule } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-single-voiture',
imports: [RouterModule],
templateUrl: './single-voiture.html',
styleUrl: './single-voiture.scss',
})
export class SingleVoiture {
name: string = 'Voiture';
status: string = 'Statut';
constructor(private service:ServiceVoiture, private route: ActivatedRoute) { }
}
Puis, dans ngOnInit() , vous allez utiliser l'objet snapshot qui contient les paramètres de l'URL et, pour l'instant, attribuer le paramètre id à la variable name :
ngOnInit() {
this.name = this.route.snapshot.params['id'];
}
Ainsi, le fragment que vous tapez dans la barre d'adresse après voitures/ s'affichera dans le template (html), mais ce n'est pas le comportement recherché.
Pour atteindre l'objectif souhaité, commencez par ajouter, dans service-voiture.service.ts , un identifiant unique pour chaque voiture et une méthode qui rendra la voiture correspondant à un identifiant :
export class VoitureService {
voitures = [
{
id: 1,
name: 'Bugatti',
status: 'Non disponible'
},
{
id: 2,
name: 'Ferrari',
status: 'Disponible'
},
{
id: 3,
name: 'Lambhorgini',
status: 'Non disponible'
}
];
getVoitureById(id: number) {
const voiture= this.voitures.find(
(voitureObject) => {
return voitureObject.id === id;
}
);
return voiture;
}

Vous pouvez naviguer manuellement vers /voitures/2 , par exemple, mais cela recharge encore la page, et vous perdez l'état des voitures (si vous en rendez Disponible ou Non disponible par exemple). Pour finaliser cette fonctionnalité, intégrez l'identifiant unique dans MarqueVoiture et dans VoitureComponentView , puis créez un "ComponentrouterLink" pour chaque voiture qui permet d'en regarder le détail
dans marques-voitures.component.ts :
@Input() voituresName: string = 'Bugatti';
@Input() voituresStatus: string = 'Non disponible';
@Input() indexdesVoiture: number = 5;
@Input() id: number = 2;
<ul class="list-group">
</ul>
<!-- <div style="width:20px;height:20px;background-color:red;"
*ngIf="voituresStatus === 'Non disponible'"></div> -->
@if (voituresStatus === 'Non disponible') {
<div style="width:20px;height:20px;background-color:red;"></div>
} @else if (voituresStatus === 'Disponible') {
<div style="width:20px;height:20px;background-color:green;"></div>
} @else { <!-- Rien du tout -->
}
<h4 [ngStyle]="{color: getColor()}">Voiture : {{ voituresName }} -- Statut : {{ getStatus() }}</h4>
<a [routerLink]=[id]>Détail</a>
<input type="text" class="form-control" [(ngModel)]="voituresName">
<input type="text" class="form-control" [(ngModel)]="voituresStatus">
Ici, vous utilisez le format array pour routerLink en property binding afin d'accéder à la variable id.
Ça y est ! Vous pouvez maintenant accéder à la page Détail pour chaque voiture, et les informations de statut qui s'y trouvent sont automatiquement à jour grâce à l'utilisation du service.
6. Redirection
Il peut y avoir des cas de figure où l'on souhaiterait rediriger un utilisateur, par exemple pour afficher une page 404 lorsqu'il entre une URL qui n'existe pas.
Pour l'application des voitures, commencez par créer un component 404 très simple, appelé four-oh-four.component.ts :
Erreur 404
La page que vous cherchez n'existe pas !
Ensuite, vous allez ajouter la route "directe" vers cette page, ainsi qu'une route "wildcard", qui redirigera toute route inconnue vers la page d'erreur :
const appRoutes: Routes = [
{ path: 'appareils', component: AppareilViewComponent },
{ path: 'appareils/:id', component: SingleAppareilComponent },
{ path: 'auth', component: AuthComponent },
{ path: '', component: AppareilViewComponent },
{ path: 'not-found', component: FourOhFourComponent },
{ path: '**', redirectTo: 'not-found' }
];
Ainsi, quand vous entrez un chemin dans la barre de navigation qui n'est pas directement pris en charge par votre application, vous êtes redirigé vers /not-found et donc le component 404.
Dans mon cas je redirige vers le component de AuthComponent
App.routes.ts
Page par défaut …
Voici mes coordonnees: Stéphane Mercier (Mers), stephane.mercier@cegeplevis.ca, 418 833-5110, poste 5511, Local G205A (disponnible par MIO)
Tout droit réservé à personne !!!
.