Afficher une donnée, c'est la leçon précédente. Maintenant : afficher conditionnellement, répéter une liste, choisir une branche. Depuis Angular 17, ça se fait avec une syntaxe à base de @ intégrée au template — @if, @for, @switch — qui remplace les vieilles directives *ngIf, *ngFor, *ngSwitch. C'est la syntaxe que tu liras et écriras chez Alliance.
@for mal écrit. C'est la grammaire des écrans.
Historiquement, le conditionnel et les boucles passaient par des directives structurelles avec une étoile : *ngIf, *ngFor. Ça marchait, mais il fallait les importer (CommonModule, NgIf, NgFor) dans chaque composant, la syntaxe du else était lourde (ng-template + référence), et c'était une source de bugs de perf. Le nouveau control flow est intégré au compilateur : rien à importer, plus lisible, plus rapide, et il comprend mieux tes types.
@if = le if, @for = le foreach, @switch = le switch. Et le @ n'est pas un hasard : c'est très proche de Razor (@if (…) { }, @foreach (var x in …) { }). Si tu sais écrire une vue Razor, tu sais déjà lire ce template. La différence reste la même qu'en leçon 04 : Razor s'exécute une fois côté serveur, Angular reste vivant et réévalue dès que la donnée change.
@if / @else if / @elseOn affiche un bloc seulement si la condition est vraie. Le @else est enfin naturel à écrire.
<!-- chargement → données → vide : un cas par branche -->
@if (chargement) {
<p>Chargement des postes…</p>
} @else if (postes.length === 0) {
<p>Aucun poste actif.</p>
} @else {
<table>…</table>
}
poste est de type Poste | null, écrire @if (poste) { {{ poste.nom }} } fait que, à l'intérieur du bloc, Angular sait que poste n'est plus null. C'est le même narrowing qu'un if (poste !== null) en TypeScript (leçon 02). Tu peux même nommer le résultat : @if (user(); as u) { {{ u.nom }} } — pratique avec les signals (phase 1).
@for — répéter une liste (avec track obligatoire)On itère sur une collection. Nouveauté majeure : le track est obligatoire. Il dit à Angular comment identifier chaque élément pour ne re-rendre que ce qui a vraiment changé.
@for (poste of postes; track poste.id) {
<tr>
<td>{{ poste.nom }}</td>
<td>{{ poste.mesure }} °C</td>
</tr>
} @empty {
<tr><td colspan="2">Liste vide</td></tr>
}
Le bloc @empty (optionnel) s'affiche quand la collection est vide — fini le @if (liste.length === 0) séparé. À l'intérieur du @for, tu disposes de variables contextuelles : $index, $first, $last, $even, $odd, $count.
@for (poste of postes; track poste.id) {
<tr [class.pair]="$even">
<td>{{ $index + 1 }}</td>
<td>{{ poste.nom }}</td>
</tr>
}
track — l'analogie clé
track poste.id, c'est comme une clé primaire : un identifiant stable qui dit « cette ligne EST ce poste ». Quand la liste change (tri, ajout, filtre), Angular compare les id et ne touche que le DOM nécessaire au lieu de tout reconstruire. C'est l'équivalent moderne du trackBy de l'ancien *ngFor — sauf qu'avant c'était optionnel (et souvent oublié), maintenant c'est imposé. Choisis toujours un identifiant stable et unique (l'id métier), pas $index.
@switch / @case / @defaultPour choisir une branche parmi plusieurs selon une valeur — typiquement un statut.
@switch (poste.statut) {
@case ('en-service') { <span class="ok">En service</span> }
@case ('alerte') { <span class="ko">⚠ Hors seuil</span> }
@default { <span>Arrêté</span> }
}
Contrairement au switch C#, pas de break : un seul @case correspond, point. Le @default est optionnel mais recommandé (le « sinon »).
| Besoin | Legacy (à savoir lire) | Moderne (à écrire) |
|---|---|---|
| Conditionnel | *ngIf | @if / @else |
| Boucle | *ngFor + trackBy | @for … ; track |
| Choix multiple | [ngSwitch] | @switch / @case |
| Import requis | CommonModule | aucun (intégré) |
Tu croiseras encore du *ngIf dans du code existant : sache le lire. Mais pour tout nouveau code, c'est @if/@for/@switch.
track $index sur une liste qui bouge (tri, filtre, suppression). L'index n'est pas stable → Angular réassocie le mauvais élément au mauvais DOM, d'où des bugs visuels (mauvais champ édité, état qui « saute »). Exige un id métier stable. (2) Pas de logique lourde dans la condition d'un @if ni dans l'expression de @for : comme en leçon 04, c'est réévalué à chaque cycle de détection — précalcule (ou computed(), phase 1). (3) Toujours prévoir le cas vide (@empty) et le cas chargement : un écran ERP sans état vide, c'est un écran cassé en démo.
@for par rapport à l'ancien *ngFor ?track choisir ?@if / @else if / @else (conditionnel, avec narrowing de type), @for (x of liste; track x.id) { } @empty { } (boucle — track obligatoire, variables $index/$first/$last/$even), @switch / @case / @default (choix multiple, sans break). Aucun import requis. Remplace *ngIf / *ngFor / [ngSwitch] (à savoir lire dans le legacy). Piège de lead : track sur un id stable, jamais $index sur une liste qui bouge.
Angular — Control flow (@if, @for, @switch) (officiel). Courte et complète. Pour le détail du re-rendu et du track : la section @for.
track $index mal choisi ? Demande-moi, ici, maintenant.