Angular Control Flow Syntax 2026: @if, @for, @switch e Domande da Colloquio
Guida completa alla nuova sintassi Control Flow di Angular con @if, @for e @switch. Ottimizzazioni delle performance, integrazione con i Signal e domande frequenti nei colloqui tecnici.

La sintassi Control Flow di Angular (@if, @for, @switch) sostituisce le direttive strutturali *ngIf, *ngFor e *ngSwitch che hanno dominato i template Angular per anni. Introdotta in Angular 17, stabile da Angular 18 e predefinita in Angular 22, questa sintassi basata su blocchi avvicina i template ai costrutti di programmazione standard, abilitando migliori ottimizzazioni delle performance.
Eseguire ng generate @angular/core:control-flow per migrare automaticamente i template esistenti dalle direttive strutturali alla nuova sintassi Control Flow. Entrambe le sintassi coesistono durante la migrazione, ma ngIf, ngFor e ngSwitch sono soft-deprecated da Angular 19.
Perché Angular ha sostituito le Direttive Strutturali con la Sintassi a Blocchi
Le direttive strutturali richiedevano l'importazione di CommonModule, utilizzavano una microsintassi diversa da JavaScript e costringevano gli sviluppatori a racchiudere i contenuti in ng-template per condizioni complesse. La nuova sintassi Control Flow risolve questi problemi:
- Nessun import richiesto:
@if,@fore@switchsono integrati nel framework - Sintassi simile a JavaScript: condizioni e cicli si leggono come codice standard
- Supporto nativo per
@else: niente più riferimenti ang-templateper i rami else - Migliore tree-shaking: i blocchi Control Flow non utilizzati hanno impatto zero sul bundle
La documentazione Angular raccomanda di adottare completamente la sintassi a blocchi in tutti i nuovi progetti e di migrare le codebase esistenti in modo incrementale.
@if: Rendering Condizionale senza ng-template
Il blocco @if renderizza condizionalmente i contenuti basandosi su un'espressione truthy. A differenza di *ngIf, supporta direttamente i rami @else if e @else:
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 }>();
}Il blocco @if supporta anche l'aliasing delle variabili con la parola chiave as, che estrae valori da espressioni annidate:
<!-- Evita accessi ripetuti alle proprietà -->
@if (user().profile?.settings?.theme; as theme) {
<p>Tema corrente: {{ theme }}</p>
}Questo pattern è particolarmente utile quando si lavora con dati async o oggetti profondamente annidati, poiché la variabile aliasata è definita solo quando la condizione è truthy.
@for: Iterazione con Espressione Track Obbligatoria
Il blocco @for itera su qualsiasi iterabile JavaScript, con ottimizzazioni per gli array. A differenza di *ngFor, richiede un'espressione 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>Nessun prodotto disponibile</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}L'espressione track indica ad Angular come identificare ogni elemento attraverso i re-render. La scelta della proprietà di tracking corretta impatta direttamente sulle performance:
| Espressione Track | Caso d'uso | Impatto sulle Performance |
|---|---|---|
track item.id | Elementi con identificatori univoci | Ottimale: aggiornamenti DOM minimi |
track $index | Liste statiche che non vengono mai riordinate | Accettabile: re-render completo al riordino |
track item | Tracking per riferimento | Scarso: nuovo riferimento = nuovo nodo DOM |
Variabili Contestuali nei Blocchi @for
Angular fornisce variabili implicite all'interno dei blocchi @for che espongono i metadati dell'iterazione:
@for (item of items(); track item.id; let i = $index, isLast = $last) {
<li class="item" [class.last]="isLast">
{{ i + 1 }}. {{ item.name }}
</li>
}Variabili contestuali disponibili:
$index: posizione zero-based$count: numero totale di elementi$first,$last: flag booleani per primo/ultimo elemento$even,$odd: flag booleani basati sulla parità dell'indice
Pronto a superare i tuoi colloqui su Angular?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
@switch: Branching Condizionale Type-Safe
Il blocco @switch fornisce pattern matching esaustivo con confronto di uguaglianza stretta (===):
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">In Attesa</span>
}
@case ('processing') {
<span class="badge badge-blue">In Elaborazione</span>
}
@case ('shipped') {
<span class="badge badge-yellow">Spedito</span>
}
@case ('delivered') {
<span class="badge badge-green">Consegnato</span>
}
}
`
})
export class StatusBadgeComponent {
status = input.required<OrderStatus>();
}A differenza dello switch JavaScript, il @switch di Angular non ha comportamento fallthrough. Condizioni multiple che puntano allo stesso blocco richiedono istruzioni @case consecutive:
@switch (userRole()) {
@case ('admin')
@case ('superadmin') {
<app-admin-dashboard />
}
@case ('editor')
@case ('reviewer') {
<app-editor-dashboard />
}
@default {
<app-viewer-dashboard />
}
}Verifica Esaustiva dei Tipi con @default never
Angular 22 supporta la verifica di esaustività a compile-time. L'uso di @default never; dichiara che non dovrebbero esistere casi rimanenti:
type Theme = 'light' | 'dark' | 'system';
// Errore di compilazione se manca un valore Theme nei blocchi @case
@switch (theme()) {
@case ('light') { /* ... */ }
@case ('dark') { /* ... */ }
@case ('system') { /* ... */ }
@default never;
}L'aggiunta di un nuovo valore all'union Theme scatena un errore di compilazione, costringendo gli sviluppatori a gestire tutti i casi.
Sintassi Control Flow e Integrazione con Angular Signals
I blocchi Control Flow si integrano perfettamente con Angular Signals, abilitando reattività granulare:
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>Nessun elemento corrisponde ai filtri</p>
}
}
`
})
export class DashboardComponent {
items = signal<Item[]>([]);
filter = signal('');
isLoading = signal(true);
hasError = signal(false);
errorMessage = signal('');
// Il signal computed viene ricalcolato solo quando cambiano le dipendenze
filteredItems = computed(() =>
this.items().filter(item =>
item.name.toLowerCase().includes(this.filter().toLowerCase())
)
);
}Quando un signal si aggiorna, Angular rivaluta solo i blocchi Control Flow interessati. Combinato con la change detection zoneless di Angular, questo abilita un rendering altamente ottimizzato.
Domande Frequenti nei Colloqui sulla Sintassi Control Flow di Angular
I colloqui tecnici testano frequentemente la comprensione della sintassi Control Flow, specialmente le differenze rispetto alle direttive strutturali.
Domanda 1: Perché track è obbligatorio in @for?
L'espressione track fornisce ad Angular un'identità stabile per ogni elemento. Senza di essa, Angular non può determinare efficientemente quali nodi DOM creare, aggiornare o distruggere quando la collezione cambia. Rendere track obbligatorio costringe gli sviluppatori a prendere una decisione esplicita sull'identità, evitando le insidie di performance del tracking implicito per riferimento.
Domanda 2: Come differisce @if da *ngIf con async pipe?
Entrambi possono gestire Observable, ma @if con i signal fornisce accesso sincrono ai valori:
// Con *ngIf e async pipe (legacy)
<div *ngIf="user$ | async as user">{{ user.name }}</div>
// Con @if e signals (moderno)
@if (user(); as user) {
<div>{{ user.name }}</div>
}L'approccio con i signal evita la gestione delle subscription e si integra meglio con la change detection di Angular.
Domanda 3: @switch può sostituire catene complesse @if/@else if?
@switch dovrebbe essere usato quando si confronta una singola espressione con valori discreti multipli. Per condizioni booleane complesse che coinvolgono espressioni diverse, @if/@else if rimane più appropriato:
<!-- Usa @switch per singola espressione, valori multipli -->
@switch (status()) {
@case ('active') { ... }
@case ('inactive') { ... }
}
<!-- Usa @if per espressioni multiple -->
@if (isAdmin() && hasPermission('write')) {
...
} @else if (isEditor()) {
...
}Domanda 4: Cosa succede a @for quando la collezione è vuota?
Quando l'iterabile non contiene elementi, Angular salta completamente il contenuto @for. Il blocco opzionale @empty renderizza contenuto di fallback in questo caso. Senza @empty, non viene renderizzato nulla, il che differisce da alcuni framework che renderizzano un contenitore vuoto.
Migrazione dalle Direttive Strutturali a Control Flow
La CLI Angular fornisce uno schematic di migrazione automatizzato:
# Migrare l'intero progetto
ng generate @angular/core:control-flow
# Migrare una directory specifica
ng generate @angular/core:control-flow --path=src/app/featuresLo schematic gestisce la maggior parte delle trasformazioni automaticamente, ma è necessario verificare l'output per i casi limite:
| Direttiva Strutturale | Equivalente Control Flow |
|---|---|
*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 |
Dopo la migrazione, rimuovere gli import di CommonModule dai componenti standalone che non utilizzano più direttive strutturali.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Punti Chiave sulla Sintassi Control Flow di Angular
- La sintassi Control Flow di Angular (
@if,@for,@switch) è l'approccio raccomandato da Angular 19, sostituendo le direttive strutturali - L'espressione
trackin@forè obbligatoria: utilizzare identificatori univoci comeitem.idper performance ottimali, evitaretrack itemche causa re-render basati su riferimento @ifsupporta nativamente i rami@else ife@elsesenzang-template, e la parola chiaveascrea alias per i valori truthy@switchutilizza uguaglianza stretta e non ha fallthrough: istruzioni@caseconsecutive puntano allo stesso blocco, e@default never;abilita la verifica esaustiva dei tipi- I blocchi Control Flow si integrano con i Signals per reattività granulare: solo i blocchi interessati vengono ri-renderizzati quando i signal si aggiornano
- Eseguire
ng generate @angular/core:control-flowper migrare automaticamente i template esistenti
Sapresti trovare il bug in Angular?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 3 settembre 2026
Tag
Condividi
Articoli correlati

Angular 20 nel 2026: Resource API, httpResource e domande da colloquio
Angular 20 introduce la Resource API e httpResource come alternative signal-based alle sottoscrizioni manuali di HttpClient. Questa guida copre tutte e tre le varianti Resource, la validazione con Zod e le domande più frequenti nei colloqui tecnici.

RxJS in Angular 2026: operatori, Subjects e interop con i Signals
RxJS in Angular 2026: operatori, Subjects e i pattern di interop con i Signals che gli sviluppatori Angular usano in produzione, più le domande da colloquio più frequenti.

Angular Signals e Computed nel 2026: Reattività Fine-Grained e Domande per Colloqui
Una guida approfondita ad Angular Signals, Computed Signals e al modello reattivo in Angular 20+. Include best practice, interoperabilità con RxJS e domande frequenti nei colloqui tecnici.