Angular Control Flow
Control flow directives (@if,@for,@switch) render branches, lists, and cases in templates and replace the legacy*ngIf/*ngFor/[ngSwitch] for new code.
Control Flow Essentials
@if: Conditional blocks with optionalelse if/else.@for: Loops withtrackfor stable identity and optional@emptyfor empty states.@switch: Selects and renders a matching case.- Preferred for new code in Angular 17+; legacy
*ngIf/*ngFor/[ngSwitch]remain supported.
@if (score > 90) { <p>A</p> } @else if (score > 75) { <p>B</p> } @else { <p>C</p> }<ul> @for (it of items; track it.id) { <li>{{ it.label }}</li> } @empty { <li>No items</li> }</ul>@switch (status) { @case ('pending') { <p>Pending</p> } @case ('done') { <p>Done</p> } @default { <p>Unknown</p> }}Code explained
@if ... @else: Branches to render different blocks based on a condition.@for (...; track ...): Iterates and usestrackto keep stable identities for DOM reuse.@switch/@case/@default: Selects and renders a matching case.
Notes:
- Related: SeeTemplates,Directives, andLists.
- Use
@forwithtrackfor stable list rendering. - Use
@if ...; elsefor readable branches.
Control Flow Basics
Toggle content with@if ...; else.
Iterate with@for and add atrack expression for stable DOM updates.
@if (show) { <p>Visible</p> } @else { <p>Hidden</p> }@for (item of items; track item) { <li>{{ item }}</li> }Example
Toggle content with@if, and render lists with@for using atrack expression:
Example
import { bootstrapApplication } from '@angular/platform-browser';import { Component, signal } from '@angular/core';@Component({ selector: 'app-root', standalone: true, template: ` <h3>Control Flow</h3> <button (click)="show.set(!show())">Toggle</button> <button (click)="items.set([])">Clear</button> <button (click)="reset()">Reset</button> @if (show()) { <p>Visible</p> } @else { <p>Hidden</p> } <ul> @for (item of items(); track item) { <li>{{ item }}</li> } @empty { <li>No items</li> } </ul> `})export class App { show = signal(true); items = signal(['One','Two','Three']); reset() { this.items.set(['One','Two','Three']); }}bootstrapApplication(App);<app-root></app-root>Example explained
@if ... @else: Toggles the paragraph based on theshow()signal.@for ... track item: Renders the list from theitems()signal and preserves DOM withtrack.@empty: Displays a fallback when the list is empty.- Signals: Buttons update
showanditems, which re-render the view.
Notes:
- Use track: Prefer tracking by a stable key (e.g.,
track it.id) for lists of objects; for primitives,track itemis fine. - Signals: Read signals with
sig()in templates (e.g.,@if (flag()),@for (x of list())). - Legacy equivalence: In
*ngFor, usetrackByto matchtrackin@for. - Legacy syntax:
*ngIf/*ngFor/[ngSwitch]remain supported; prefer@if/@for/@switchfor new code. - Keep logic in TS: Compute flags and derived arrays in the component; keep templates simple.
- No side effects: Avoid side effects inside control-flow blocks; update state in handlers/services.

