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.

Diagramma della sintassi Control Flow di Angular con blocchi @if, @for e @switch

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.

Migrazione disponibile

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, @for e @switch sono integrati nel framework
  • Sintassi simile a JavaScript: condizioni e cicli si leggono come codice standard
  • Supporto nativo per @else: niente più riferimenti a ng-template per 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:

user-status.component.tstypescript
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:

html
<!-- 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:

product-list.component.tstypescript
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 TrackCaso d'usoImpatto sulle Performance
track item.idElementi con identificatori univociOttimale: aggiornamenti DOM minimi
track $indexListe statiche che non vengono mai riordinateAccettabile: re-render completo al riordino
track itemTracking per riferimentoScarso: 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:

html
@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 (===):

status-badge.component.tstypescript
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:

html
@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:

typescript
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:

dashboard.component.tstypescript
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:

typescript
// 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:

html
<!-- 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:

bash
# Migrare l'intero progetto
ng generate @angular/core:control-flow

# Migrare una directory specifica
ng generate @angular/core:control-flow --path=src/app/features

Lo schematic gestisce la maggior parte delle trasformazioni automaticamente, ma è necessario verificare l'output per i casi limite:

Direttiva StrutturaleEquivalente 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 track in @for è obbligatoria: utilizzare identificatori univoci come item.id per performance ottimali, evitare track item che causa re-render basati su riferimento
  • @if supporta nativamente i rami @else if e @else senza ng-template, e la parola chiave as crea alias per i valori truthy
  • @switch utilizza uguaglianza stretta e non ha fallthrough: istruzioni @case consecutive 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-flow per migrare automaticamente i template esistenti
Sfida del giorno

Sapresti trovare il bug in Angular?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore 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

#angular
#control-flow
#typescript
#template-syntax
#signals

Condividi

Articoli correlati