Angular v21 introduces a brand-new control flow syntax in templates using the @ symbol. This syntax works seamlessly with signals and allows much cleaner, reactive, and readable templates.
#@if Directive
The @if directive replaces *ngIf and works directly with signals or expressions.
Basic usage:
<div @if="isLoggedIn()">
Welcome back!
</div>
<div @else>
Please log in.
</div>
Assign the value to a local variable:
<div @if="userSignal() as user; else guest">
Hello, {{ user.name }}!
</div>
<div @template #guest>
Welcome, guest!
</div>
#@for Directive
The @for directive replaces *ngFor and supports destructuring inline.
<ul>
<li @for="let item of itemsSignal(); let i = index; let isFirst = first">
{{ i }}: {{ item }} <span @if="isFirst">(First)</span>
</li>
</ul>
#@switch Directive
Angular v21 introduces @switch as a modern replacement for ngSwitch.
<div @switch="statusSignal()">
<div @case="'loading'">Loading...</div>
<div @case="'success'">Data loaded!</div>
<div @case="'error'">Error occurred.</div>
<div @default>Unknown status</div>
</div>
#Nested Control Flow
Nested @if and @for work naturally:
<ul>
<li @for="let user of usersSignal(); let isLast = last">
{{ user.name }}
<span @if="isLast">(last user)</span>
</li>
</ul>
#Combining @if + @for
You can combine loops and conditions in a concise way:
<div @for="let task of tasksSignal()">
<span @if="task.completed">✔</span>
{{ task.name }}
</div>
#Key Advantages
- Templates are more readable than nested *ngIf/*ngFor
- Fully reactive with signals
- Inline
asvariables improve template clarity - Default/else blocks are explicit with
@elseor@default
#Real-World Example
<div @if="todosSignal().length > 0; else noTodos">
<ul>
<li @for="let todo of todosSignal()">
<span @if="todo.done">✔</span>
{{ todo.title }}
</li>
</ul>
</div>
<div @template #noTodos>No tasks available.</div>
#Conclusion
The @ control flow syntax in Angular v21 simplifies templates, enhances readability, and integrates seamlessly with signals. This makes dynamic templates easier to maintain and more performant, replacing the older *ngIf, *ngFor, and ngSwitch patterns.