La version 17 du framework Angular a vu l’ajout d’une nouvelle syntaxe du contrôle de flux visant à améliorer l’écriture des templates des composants Angular.
Cette nouveauté a plusieurs avantages :
- Code des templates simplifiés et mieux lisibles
- Meilleur contrôle des types des variables utilisés
- Meilleures performances lors du rendu des composants
- Elle permet de s’affranchir d’importer les différentes directives nécessaires pour les utiliser dans nos composants. En effet cette nouvelle syntaxe est nativement intégrée au moteur de template
Tour d’horizon rapide des nouveaux blocs
Bloc if – then – else
Il fallait jusqu’à la version 16 du framework utiliser la directive *ngIf pour afficher de manière conditionnelle certains blocs :
1 2 3 4 5 6 |
<div *ngIf="condition; else elseBlock"> Contenu si la condition est vraie. </div> <ng-template #elseBlock> Contenu si la condition est fausse. </ng-template> |
Depuis Angular 17 il est désormais possible d’utiliser la syntaxe simplifiée suivante :
1 2 3 4 5 6 7 |
<div> @if (condition) { Contenu si la condition est vraie. } @else { Contenu si la condition est fausse. } </div> |
Encore mieux, il est désormais possible d’utiliser la condition else if, ce qui n’était jusqu’ici pas possible en utilisant la directive *ngIf :
1 2 3 4 5 6 7 8 9 10 11 |
<div> @if (condition_A) { Contenu si la condition A est vraie. } @else if (condition_B) { Contenu si la condition A est fausse et si la condition B est vraie. } @else { Contenu si les conditions A et B sont fausses. } </div> |
Bloc for
La directive *ngFor permettant d’itérer sur une liste d’éléments s’utilise de la manière suivante :
1 2 3 |
<ul> <li *ngFor="let item of items">{{ item.name }}</li> </ul> |
La version Angular 17 s’écrit désormais via la syntaxe suivante :
1 2 3 4 5 |
<ul> @for (item of items) { <li>{{ item.name }}</li> } </ul> |
Nouveauté également pour le bloc for, il est désormais possible d’utiliser le bloc @empty afin d’afficher un contenu spécifique lorsque la collection ne comporte aucun élément :
1 2 3 4 5 6 7 |
<ul> @for (item of items; track item.name) { <li>{{ item.name }}</li> } @empty { <li>Aucun élément</li> } </ul> |
Bloc switch – case
Commençons par rappeler la syntaxe que nous devions utiliser jusqu’à l’arrivée d’Angular 17 :
1 2 3 4 5 |
<div [ngSwitch]="page"> <p *ngSwitchCase="1">Contenu de la première page</p> <p *ngSwitchCase="2">Contenu de la deuxième page</p> <p *ngSwitchDefault>Aucune page sélectionnée</p> </div> |
La nouvelle syntaxe s’écrit de la manière suivante :
1 2 3 4 5 6 7 8 9 10 11 |
@switch (page) { @case (1) { <p>Contenu de la première page</p> } @case (2) { <p>Contenu de la deuxième page</p> } @default { <p>Aucune page sélectionnée</p> } } |
Le bloc @default est ici optionnel, si aucun bloc @case ne répond à la condition, le template n’affichera aucun contenu.
Utilisation du pipe async
Les développeurs Angular le savent, il faut absolument éviter de souscrire manuellement à des observables via le code de leur composants (principalement pour laisser le framework gérer le désabonnement automatiquement via le cycle de vie des composants et ne pas causer de fuites).
La solution jusqu’à Angular 16 était d’utiliser le pipe async en combinaison d’une des directives dans le template du composant.
Par exemple ici un *ngIf :
1 2 3 |
<ng-container *ngIf="data$ | async as data"> {{ data.element }} <ng-container> |
La nouvelle syntaxe introduite par Angular 17 est la suivante :
1 2 3 |
@if (data$ | async; as data) { {{data.element}} } |
Migration simplifiée
Angular CLI propose une solution rapide pour migrer l’ensemble des directives *ngIf *ngFor et *ngSwitch :
1 |
ng generate @angular/core:control-flow |