Angular Control Flow Syntax 2026: @if, @for, @switch und Interviewfragen
Umfassende Anleitung zur neuen Angular Control Flow Syntax mit @if, @for und @switch. Performance-Optimierungen, Signal-Integration und häufige Interviewfragen für Angular-Entwickler.

Die Control Flow Syntax von Angular (@if, @for, @switch) ersetzt die strukturellen Direktiven *ngIf, *ngFor und *ngSwitch, die jahrelang Angular-Templates dominierten. Eingeführt in Angular 17, stabil seit Angular 18 und Standard in Angular 22, bringt diese block-basierte Syntax Templates näher an Standard-Programmierkonstrukte und ermöglicht bessere Performance-Optimierungen.
Mit ng generate @angular/core:control-flow lassen sich bestehende Templates automatisch von strukturellen Direktiven zur neuen Control Flow Syntax migrieren. Beide Syntaxen koexistieren während der Migration, aber ngIf, ngFor und ngSwitch sind seit Angular 19 soft-deprecated.
Warum Angular strukturelle Direktiven durch Block-Syntax ersetzt hat
Strukturelle Direktiven erforderten den Import von CommonModule, verwendeten Microsyntax, die sich von JavaScript unterschied, und zwangen Entwickler dazu, Inhalte für komplexe Bedingungen in ng-template zu wrappen. Die neue Control Flow Syntax löst diese Probleme:
- Keine Imports erforderlich:
@if,@forund@switchsind ins Framework integriert - JavaScript-ähnliche Syntax: Bedingungen und Schleifen lesen sich wie Standardcode
- Native
@else-Unterstützung: keineng-template-Referenzen mehr für else-Zweige - Besseres Tree-Shaking: ungenutzte Control Flow Blocks haben keinen Einfluss auf die Bundle-Größe
Die Angular-Dokumentation empfiehlt, die Block-Syntax in allen neuen Projekten vollständig zu übernehmen und bestehende Codebasen schrittweise zu migrieren.
@if: Bedingtes Rendering ohne ng-template
Der @if-Block rendert Inhalte bedingt basierend auf einem truthy Ausdruck. Im Gegensatz zu *ngIf unterstützt er @else if und @else-Zweige direkt:
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 }>();
}Der @if-Block unterstützt auch Variablen-Aliasing mit dem as-Schlüsselwort, das Werte aus verschachtelten Ausdrücken extrahiert:
<!-- Vermeidet wiederholten Property-Zugriff -->
@if (user().profile?.settings?.theme; as theme) {
<p>Aktuelles Theme: {{ theme }}</p>
}Dieses Muster ist besonders nützlich bei der Arbeit mit async Daten oder tief verschachtelten Objekten, da die aliasierte Variable nur definiert ist, wenn die Bedingung truthy ist.
@for: Iteration mit obligatorischem Track-Ausdruck
Der @for-Block iteriert über jedes JavaScript-Iterable mit Optimierungen für Arrays. Im Gegensatz zu *ngFor erfordert er einen track-Ausdruck:
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>Keine Produkte verfügbar</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}Der track-Ausdruck teilt Angular mit, wie jedes Element über Re-Renders hinweg identifiziert werden soll. Die Wahl der richtigen Tracking-Property hat direkten Einfluss auf die Performance:
| Track-Ausdruck | Anwendungsfall | Performance-Auswirkung |
|---|---|---|
track item.id | Elemente mit eindeutigen Identifiern | Optimal: minimale DOM-Updates |
track $index | Statische Listen, die nie umsortiert werden | Akzeptabel: vollständiges Re-Render bei Umsortierung |
track item | Referenz-Tracking | Schlecht: neue Referenz = neuer DOM-Knoten |
Kontextvariablen in @for-Blöcken
Angular stellt implizite Variablen innerhalb von @for-Blöcken bereit, die Iterations-Metadaten exponieren:
@for (item of items(); track item.id; let i = $index, isLast = $last) {
<li class="item" [class.last]="isLast">
{{ i + 1 }}. {{ item.name }}
</li>
}Verfügbare Kontextvariablen:
$index: nullbasierte Position$count: Gesamtanzahl der Elemente$first,$last: Boolean-Flags für erstes/letztes Element$even,$odd: Boolean-Flags basierend auf Index-Parität
Bereit für deine Angular-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
@switch: Typsichere bedingte Verzweigung
Der @switch-Block bietet erschöpfendes Pattern Matching mit striktem Gleichheitsvergleich (===):
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">Ausstehend</span>
}
@case ('processing') {
<span class="badge badge-blue">In Bearbeitung</span>
}
@case ('shipped') {
<span class="badge badge-yellow">Versendet</span>
}
@case ('delivered') {
<span class="badge badge-green">Zugestellt</span>
}
}
`
})
export class StatusBadgeComponent {
status = input.required<OrderStatus>();
}Im Gegensatz zu JavaScripts switch hat Angulars @switch kein Fallthrough-Verhalten. Mehrere Bedingungen, die denselben Block ansteuern, erfordern aufeinanderfolgende @case-Anweisungen:
@switch (userRole()) {
@case ('admin')
@case ('superadmin') {
<app-admin-dashboard />
}
@case ('editor')
@case ('reviewer') {
<app-editor-dashboard />
}
@default {
<app-viewer-dashboard />
}
}Erschöpfende Typprüfung mit @default never
Angular 22 unterstützt Compile-Time Exhaustiveness Checking. Die Verwendung von @default never; deklariert, dass keine verbleibenden Fälle existieren sollten:
type Theme = 'light' | 'dark' | 'system';
// Kompilierfehler, wenn ein Theme-Wert in den @case-Blöcken fehlt
@switch (theme()) {
@case ('light') { /* ... */ }
@case ('dark') { /* ... */ }
@case ('system') { /* ... */ }
@default never;
}Das Hinzufügen eines neuen Wertes zur Theme-Union löst einen Kompilierfehler aus und zwingt Entwickler, alle Fälle zu behandeln.
Control Flow Syntax und Angular Signals Integration
Control Flow Blocks integrieren sich nahtlos mit Angular Signals und ermöglichen feinkörnige Reaktivität:
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>Keine Elemente entsprechen Ihren Filtern</p>
}
}
`
})
export class DashboardComponent {
items = signal<Item[]>([]);
filter = signal('');
isLoading = signal(true);
hasError = signal(false);
errorMessage = signal('');
// Computed Signal wird nur neu berechnet, wenn sich Abhängigkeiten ändern
filteredItems = computed(() =>
this.items().filter(item =>
item.name.toLowerCase().includes(this.filter().toLowerCase())
)
);
}Wenn sich ein Signal aktualisiert, evaluiert Angular nur die betroffenen Control Flow Blocks neu. Kombiniert mit Angulars zoneless Change Detection ermöglicht dies hochoptimiertes Rendering.
Häufige Interviewfragen zur Angular Control Flow Syntax
Technische Interviews testen häufig das Verständnis der Control Flow Syntax, insbesondere die Unterschiede zu strukturellen Direktiven.
Frage 1: Warum ist track in @for obligatorisch?
Der track-Ausdruck gibt Angular eine stabile Identität für jedes Element. Ohne ihn kann Angular nicht effizient bestimmen, welche DOM-Knoten erstellt, aktualisiert oder zerstört werden sollen, wenn sich die Collection ändert. Die Pflicht von track zwingt Entwickler zu einer expliziten Entscheidung über Identität und vermeidet die Performance-Fallen von implizitem Referenz-Tracking.
Frage 2: Wie unterscheidet sich @if von *ngIf mit async pipe?
Beide können Observables verarbeiten, aber @if mit Signals bietet synchronen Zugriff auf Werte:
// Mit *ngIf und async pipe (Legacy)
<div *ngIf="user$ | async as user">{{ user.name }}</div>
// Mit @if und Signals (modern)
@if (user(); as user) {
<div>{{ user.name }}</div>
}Der Signal-Ansatz vermeidet Subscription-Management und integriert sich besser mit Angulars Change Detection.
Frage 3: Kann @switch komplexe @if/@else if-Ketten ersetzen?
@switch sollte verwendet werden, wenn ein einzelner Ausdruck mit mehreren diskreten Werten verglichen wird. Für komplexe Boolean-Bedingungen, die verschiedene Ausdrücke involvieren, bleibt @if/@else if angemessener:
<!-- Verwende @switch für einzelnen Ausdruck, mehrere Werte -->
@switch (status()) {
@case ('active') { ... }
@case ('inactive') { ... }
}
<!-- Verwende @if für mehrere Ausdrücke -->
@if (isAdmin() && hasPermission('write')) {
...
} @else if (isEditor()) {
...
}Frage 4: Was passiert mit @for, wenn die Collection leer ist?
Wenn das Iterable keine Elemente enthält, überspringt Angular den @for-Inhalt vollständig. Der optionale @empty-Block rendert Fallback-Inhalt in diesem Fall. Ohne @empty wird nichts gerendert, was sich von einigen Frameworks unterscheidet, die einen leeren Container rendern.
Migration von strukturellen Direktiven zu Control Flow
Die Angular CLI bietet ein automatisiertes Migrations-Schematic:
# Gesamtes Projekt migrieren
ng generate @angular/core:control-flow
# Bestimmtes Verzeichnis migrieren
ng generate @angular/core:control-flow --path=src/app/featuresDas Schematic handhabt die meisten Transformationen automatisch, aber überprüfen Sie die Ausgabe auf Grenzfälle:
| Strukturelle Direktive | Control Flow Äquivalent |
|---|---|
*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 |
Nach der Migration entfernen Sie CommonModule-Imports aus Standalone-Komponenten, die keine strukturellen Direktiven mehr verwenden.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Wichtige Erkenntnisse zur Angular Control Flow Syntax
- Angulars Control Flow Syntax (
@if,@for,@switch) ist seit Angular 19 der empfohlene Ansatz und ersetzt strukturelle Direktiven - Der
track-Ausdruck in@forist obligatorisch: Verwenden Sie eindeutige Identifier wieitem.idfür optimale Performance, vermeiden Sietrack item, das referenzbasierte Re-Renders verursacht @ifunterstützt native@else ifund@else-Zweige ohneng-template, und dasas-Schlüsselwort aliasiert truthy Werte zur Wiederverwendung@switchverwendet strikte Gleichheit und hat kein Fallthrough: aufeinanderfolgende@case-Anweisungen zielen auf denselben Block, und@default never;ermöglicht erschöpfende Typprüfung- Control Flow Blocks integrieren sich mit Signals für feinkörnige Reaktivität: nur betroffene Blöcke werden neu gerendert, wenn sich Signals aktualisieren
- Führen Sie
ng generate @angular/core:control-flowaus, um bestehende Templates automatisch zu migrieren
Findest du den Bug in Angular?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 3. September 2026
Tags
Teilen
Verwandte Artikel

Angular 20 im Jahr 2026: Resource API, httpResource und Interviewfragen
Angular 20 führt die Resource API und httpResource als signalbasierte Alternativen zu manuellen HttpClient-Subscriptions ein. Dieser Leitfaden behandelt alle drei Resource-Varianten, Zod-Validierung und häufige Interviewfragen.

RxJS in Angular 2026: Operatoren, Subjects und Signals-Interop
RxJS in Angular 2026: Operatoren, Subjects und die Signals-Interop-Muster, die Angular-Entwickler in Produktion nutzen, plus die häufigsten Interviewfragen.

Angular Signals und Computed 2026: Fein-granulare Reaktivität und Interview-Fragen
Ein tiefgehender Leitfaden zu Angular Signals, Computed Signals und dem reaktiven Modell in Angular 20+. Enthält Best Practices, RxJS-Interoperabilität und häufige technische Interview-Fragen.