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 
trackin@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 
asbinding (e.g.,@if (expr; as value)) is block-scoped; it isn’t visible outside the@ifblock. - 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.