New Control Flow
New Control Flow
Section titled “New Control Flow”@if (items.length) { <li @for (item of items; track item.id)>{{ item.name }}</li>}
Notes
- Replaces many structural directive use cases with built-ins.
Before vs After
Section titled “Before vs After”Before (Angular ≤ v16 — structural directives)
Section titled “Before (Angular ≤ v16 — structural directives)”<!-- *ngIf with else template --><div *ngIf="items?.length; else empty"> <ul> <li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li> </ul></div><ng-template #empty> <p>No items</p></ng-template>
trackById(index: number, item: { id: number }) { return item.id; }
After (Angular v17+ — new control flow)
Section titled “After (Angular v17+ — new control flow)”@if (items?.length > 0) { <ul> @for (item of items; track item.id) { <li>{{ item.name }}</li> } </ul>} @else { <p>No items</p>}
Async values (before/after)
Section titled “Async values (before/after)”Before
Section titled “Before”<div *ngIf="user$ | async as user; else loading"> Hello {{ user.name }}</div><ng-template #loading>Loading…</ng-template>
@if (user$ | async; as user) { Hello {{ user.name }}} @else { Loading…}
Else-if chain
Section titled “Else-if chain”@if (status === 'loading') { <p>Loading…</p>} @else if (status === 'error') { <p>Something went wrong.</p>} @else { <p>Ready!</p>}
Pitfalls
Section titled “Pitfalls”- Always provide a stable key with
track
in@for
(e.g.,track item.id
) to avoid DOM churn. - Don’t mix old structural directives (
*ngIf
,*ngFor
) with new syntax on the same element; wrap or nest instead. - The
as
binding (e.g.,@if (expr; as value)
) is block-scoped; it isn’t visible outside the@if
block. - Use parentheses for complex conditions to keep expressions clear and avoid precedence surprises.
- Avoid non-deterministic expressions (like
Math.random()
/Date.now()
) inside control flow when doing SSR to prevent hydration mismatches.