Structural Directives
Conditionally rendering and repeating template content with @if and @for, Angular's modern control-flow syntax.
読了時間 2 分
Most templates need to show something only sometimes, or show a list of something a variable number of times. Angular calls this control flow, and modern Angular handles it with @if and @for blocks built directly into the template syntax.
Conditional rendering with @if
<div class="banner">
@if (user.isPremium) {
<p>Thanks for being a premium member!</p>
} @else if (user.trialDaysLeft > 0) {
<p>{{ user.trialDaysLeft }} days left in your trial.</p>
} @else {
<p>Upgrade to unlock premium features.</p>
}
</div>Unlike a plain CSS display: none, an @if block that evaluates to false is never rendered into the DOM at all — the elements inside it don't exist until the condition is true. That matters for performance (nothing to render) and for correctness (no risk of a hidden element being focused or read by a screen reader by mistake).
Repeating content with @for
<ul>
@for (task of tasks; track task.id) {
<li [class.done]="task.completed">{{ task.title }}</li>
} @empty {
<li>No tasks yet.</li>
}
</ul>export class TaskListComponent {
tasks = [
{ id: 1, title: 'Write lesson content', completed: false },
{ id: 2, title: 'Review pull request', completed: true },
];
}The track expression is required, not optional — it tells Angular how to identify each item across re-renders, usually a stable unique id. Without a good tracking key, Angular can't tell "this item moved" from "this item was removed and a new one was added," and ends up destroying and recreating DOM elements unnecessarily whenever the list changes. The @empty block renders in place of the loop when the list has zero items, replacing the manual *ngIf="tasks.length === 0" check you'd otherwise write alongside it.
The older syntax you'll still see
Before this block syntax arrived in Angular 17, the same behavior was written as attribute directives with an asterisk:
<li *ngFor="let task of tasks; trackBy: trackById">{{ task.title }}</li>
<p *ngIf="user.isPremium">Thanks for being a premium member!</p>*ngFor and *ngIf still work and you'll run into them constantly in existing codebases and tutorials, but they require importing CommonModule and are gradually being phased out in favor of @if/@for, which are built into the template compiler directly, produce clearer error messages, and don't need an import at all. New code should default to the block syntax; recognizing the asterisk syntax is mainly for reading older code.