Syntaxe de flux de contrôle Angular en 2026 : @if, @for, @switch et questions d'entretien
Guide complet sur la syntaxe de flux de contrôle Angular avec @if, @for et @switch. Apprenez à remplacer les directives structurelles par les blocs de contrôle modernes et préparez-vous aux entretiens techniques.

La syntaxe de flux de contrôle Angular (@if, @for, @switch) remplace les directives structurelles *ngIf, *ngFor et *ngSwitch qui dominaient les templates Angular depuis des années. Introduite dans Angular 17, stabilisée depuis Angular 18 et devenue la syntaxe par défaut dans Angular 22, cette approche basée sur des blocs rapproche les templates des constructions de programmation standard tout en permettant de meilleures optimisations de performance.
Exécutez ng generate @angular/core:control-flow pour migrer automatiquement les templates existants des directives structurelles vers la nouvelle syntaxe de flux de contrôle. Les deux syntaxes coexistent pendant la migration, mais ngIf, ngFor et ngSwitch sont dépréciées de manière douce depuis Angular 19.
Pourquoi Angular a remplacé les directives structurelles par la syntaxe de blocs
Les directives structurelles nécessitaient l'import de CommonModule, utilisaient une microsyntaxe différente de JavaScript et forçaient les développeurs à envelopper le contenu dans des ng-template pour les conditions complexes. La nouvelle syntaxe de flux de contrôle résout ces problèmes :
- Aucun import requis :
@if,@foret@switchsont intégrés au framework - Syntaxe proche de JavaScript : les conditions et boucles se lisent comme du code standard
- Support natif de
@else: plus besoin de référencesng-templatepour les branches else - Meilleur tree-shaking : les blocs de flux de contrôle non utilisés n'ont aucun impact sur la taille du bundle
La documentation Angular recommande d'adopter pleinement la syntaxe de blocs dans tous les nouveaux projets et de migrer progressivement les bases de code existantes.
@if : Rendu conditionnel sans ng-template
Le bloc @if rend conditionnellement du contenu basé sur une expression véridique. Contrairement à *ngIf, il supporte les branches @else if et @else directement :
import { Component, input } from '@angular/core';
@Component({
selector: 'app-user-status',
template: `
@if (user().role === 'admin') {
<app-admin-panel />
} @else if (user().role === 'editor') {
<app-editor-panel />
} @else {
<app-viewer-panel />
}
`
})
export class UserStatusComponent {
user = input.required<{ role: string }>();
}Le bloc @if supporte également l'aliasing de variables avec le mot-clé as, qui extrait les valeurs des expressions imbriquées :
<!-- Évite les accès répétés aux propriétés -->
@if (user().profile?.settings?.theme; as theme) {
<p>Thème actuel : {{ theme }}</p>
}Ce pattern est particulièrement utile lors du travail avec des données asynchrones ou des objets profondément imbriqués, puisque la variable aliasée n'est définie que lorsque la condition est véridique.
@for : Itération avec expression track obligatoire
Le bloc @for itère sur tout itérable JavaScript, avec des optimisations pour les tableaux. Contrairement à *ngFor, il nécessite une expression track :
import { Component, input } from '@angular/core';
interface Product {
id: string;
name: string;
price: number;
}
@Component({
selector: 'app-product-list',
template: `
@for (product of products(); track product.id) {
<app-product-card [product]="product" />
} @empty {
<p>Aucun produit disponible</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}L'expression track indique à Angular comment identifier chaque élément entre les re-rendus. Le choix de la bonne propriété de tracking impacte directement les performances :
| Expression Track | Cas d'utilisation | Impact performance |
|---|---|---|
track item.id | Éléments avec identifiants uniques | Optimal : mises à jour DOM minimales |
track $index | Listes statiques qui ne se réordonnent jamais | Acceptable : re-rendu complet lors du réordonnancement |
track item | Tracking par référence | Mauvais : nouvelle référence = nouveau nœud DOM |
Variables contextuelles dans les blocs @for
Angular fournit des variables implicites à l'intérieur des blocs @for qui exposent les métadonnées d'itération :
@for (item of items(); track item.id; let i = $index, isLast = $last) {
<li class="item" [class.last]="isLast">
{{ i + 1 }}. {{ item.name }}
</li>
}Variables contextuelles disponibles :
$index: position base zéro$count: nombre total d'éléments$first,$last: flags booléens pour le premier/dernier élément$even,$odd: flags booléens basés sur la parité de l'index
Prêt à réussir tes entretiens Angular ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
@switch : Branchement conditionnel type-safe
Le bloc @switch fournit un pattern matching exhaustif avec comparaison d'égalité stricte (===) :
import { Component, input } from '@angular/core';
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';
@Component({
selector: 'app-status-badge',
template: `
@switch (status()) {
@case ('pending') {
<span class="badge badge-gray">En attente</span>
}
@case ('processing') {
<span class="badge badge-blue">En cours</span>
}
@case ('shipped') {
<span class="badge badge-yellow">Expédié</span>
}
@case ('delivered') {
<span class="badge badge-green">Livré</span>
}
}
`
})
export class StatusBadgeComponent {
status = input.required<OrderStatus>();
}Contrairement au switch JavaScript, le @switch d'Angular n'a pas de comportement fallthrough. Les conditions multiples ciblant le même bloc nécessitent des instructions @case consécutives :
@switch (userRole()) {
@case ('admin')
@case ('superadmin') {
<app-admin-dashboard />
}
@case ('editor')
@case ('reviewer') {
<app-editor-dashboard />
}
@default {
<app-viewer-dashboard />
}
}Vérification de type exhaustive avec @default never
Angular 22 supporte la vérification d'exhaustivité à la compilation. L'utilisation de @default never; déclare qu'aucun cas restant ne devrait exister :
type Theme = 'light' | 'dark' | 'system';
// Erreur de compilation si une valeur Theme manque dans les blocs @case
@switch (theme()) {
@case ('light') { /* ... */ }
@case ('dark') { /* ... */ }
@case ('system') { /* ... */ }
@default never;
}L'ajout d'une nouvelle valeur à l'union Theme déclenche une erreur de compilation, forçant les développeurs à gérer tous les cas.
Intégration de la syntaxe de flux de contrôle avec les Signals Angular
Les blocs de flux de contrôle s'intègrent parfaitement avec les Signals Angular, permettant une réactivité fine :
import { Component, computed, signal } from '@angular/core';
@Component({
selector: 'app-dashboard',
template: `
@if (isLoading()) {
<app-skeleton />
} @else if (hasError()) {
<app-error [message]="errorMessage()" />
} @else {
@for (item of filteredItems(); track item.id) {
<app-item-card [item]="item" />
} @empty {
<p>Aucun élément ne correspond à vos filtres</p>
}
}
`
})
export class DashboardComponent {
items = signal<Item[]>([]);
filter = signal('');
isLoading = signal(true);
hasError = signal(false);
errorMessage = signal('');
// Le signal computed ne recalcule que lorsque les dépendances changent
filteredItems = computed(() =>
this.items().filter(item =>
item.name.toLowerCase().includes(this.filter().toLowerCase())
)
);
}Lorsqu'un signal se met à jour, Angular réévalue uniquement les blocs de flux de contrôle affectés. Combiné avec la détection de changement zoneless d'Angular, cela permet un rendu hautement optimisé.
Questions d'entretien fréquentes sur le flux de contrôle Angular
Les entretiens techniques testent fréquemment la compréhension de la syntaxe de flux de contrôle, particulièrement les différences avec les directives structurelles.
Question 1 : Pourquoi track est-il obligatoire dans @for ?
L'expression track fournit à Angular une identité stable pour chaque élément. Sans elle, Angular ne peut pas déterminer efficacement quels nœuds DOM créer, mettre à jour ou détruire lorsque la collection change. Rendre track obligatoire force les développeurs à prendre une décision explicite sur l'identité, évitant les pièges de performance du tracking implicite par référence.
Question 2 : Comment @if diffère-t-il de *ngIf avec async pipe ?
Les deux peuvent gérer les observables, mais @if avec les signals fournit un accès synchrone aux valeurs :
// Avec *ngIf et async pipe (legacy)
<div *ngIf="user$ | async as user">{{ user.name }}</div>
// Avec @if et signals (moderne)
@if (user(); as user) {
<div>{{ user.name }}</div>
}L'approche avec signals évite la gestion des subscriptions et s'intègre mieux avec la détection de changement d'Angular.
Question 3 : @switch peut-il remplacer les chaînes complexes @if/@else if ?
@switch devrait être utilisé lors de la comparaison d'une seule expression avec plusieurs valeurs discrètes. Pour les conditions booléennes complexes impliquant différentes expressions, @if/@else if reste plus approprié :
<!-- Utiliser @switch pour une seule expression, plusieurs valeurs -->
@switch (status()) {
@case ('active') { ... }
@case ('inactive') { ... }
}
<!-- Utiliser @if pour plusieurs expressions -->
@if (isAdmin() && hasPermission('write')) {
...
} @else if (isEditor()) {
...
}Question 4 : Que se passe-t-il avec @for lorsque la collection est vide ?
Lorsque l'itérable ne contient aucun élément, Angular ignore entièrement le contenu du @for. Le bloc optionnel @empty rend du contenu de secours dans ce cas. Sans @empty, rien n'est rendu, ce qui diffère de certains frameworks qui rendent un conteneur vide.
Migration des directives structurelles vers le flux de contrôle
La CLI Angular fournit un schématic de migration automatisé :
# Migrer le projet entier
ng generate @angular/core:control-flow
# Migrer un répertoire spécifique
ng generate @angular/core:control-flow --path=src/app/featuresLe schématic gère automatiquement la plupart des transformations, mais il faut vérifier la sortie pour les cas limites :
| Directive structurelle | Équivalent flux de contrôle |
|---|---|
*ngIf="condition" | @if (condition) { } |
*ngIf="condition; else elseBlock" | @if (condition) { } @else { } |
*ngFor="let item of items" | @for (item of items; track item) { } |
*ngFor="let item of items; index as i" | @for (item of items; track item; let i = $index) { } |
[ngSwitch] + *ngSwitchCase | @switch + @case |
Après la migration, supprimez les imports CommonModule des composants standalone qui n'utilisent plus les directives structurelles.
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Points clés sur la syntaxe de flux de contrôle Angular
- La syntaxe de flux de contrôle Angular (
@if,@for,@switch) est l'approche recommandée depuis Angular 19, remplaçant les directives structurelles - L'expression
trackdans@forest obligatoire : utilisez des identifiants uniques commeitem.idpour des performances optimales, éviteztrack itemqui cause des re-rendus basés sur les références @ifsupporte les branches natives@else ifet@elsesansng-template, et le mot-cléascrée des alias pour les valeurs véridiques pour réutilisation@switchutilise l'égalité stricte et n'a pas de fallthrough : les instructions@caseconsécutives ciblent le même bloc, et@default never;active la vérification de type exhaustive- Les blocs de flux de contrôle s'intègrent avec les Signals pour une réactivité fine : seuls les blocs affectés se re-rendent lorsque les signals se mettent à jour
- Exécutez
ng generate @angular/core:control-flowpour migrer automatiquement les templates existants
Tu saurais repérer le bug en Angular ?
Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Écrit par
Anthony Fillion-MailletFondateur de SharpSkill
Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.
Mis à jour le 3 septembre 2026
Tags
Partager
Articles similaires

Angular Signals et Computed en 2026 : Réactivité Fine et Questions d'Entretien
Maîtriser les Signals Angular, computed, effect et linkedSignal dans Angular 20+. Patterns de réactivité fine et préparation aux entretiens techniques.

Angular 19 en entretien : Signals, SSR et les questions incontournables
Les questions d'entretien Angular 19 les plus fréquentes : Signals, SSR avec hydratation incrémentale, détection de changement zoneless et nouvelles API réactives.

RxJS dans Angular 2026 : operators, Subjects et interop Signals
RxJS dans Angular 2026 : maîtriser les operators, les Subjects et les patterns d'interop Signals utilisés en production, ainsi que les questions d'entretien les plus fréquentes.