Angular Control Flow vs Structural Directives: The End of *ngIf and *ngFor?

Felipe Norato
3 min readFeb 7, 2025

--

With Angular 17, a major shift in template control flow was introduced: Control Flow Blocks. This new approach replaces structural directives like *ngIf, *ngFor, and *ngSwitch, making code cleaner and more performant.

This article will compare Control Flow Blocks with traditional structural directives, highlighting the changes, advantages, and scenarios where the new approach shines.

📌 The Problem with Structural Directives (*ngIf, *ngFor, *ngSwitch)

Before Angular 17, conditional rendering and iteration in templates were handled with structural directives such as:

✅ Traditional *ngIf Example

<p *ngIf="user.isAdmin">Welcome, admin!</p>

Issues with *ngIf:

  • Requires ng-container to avoid extra DOM elements.
  • Nested *ngIf structures make templates harder to read.

✅ Traditional *ngFor Example

<ul>
<li *ngFor="let item of items; index as i">{{ i }} - {{ item }}</li>
</ul>

Issues with *ngFor:

  • Always requires a wrapper element (even if unnecessary for styling or layout).

✅ Traditional *ngSwitch Example

<div [ngSwitch]="status">
<p *ngSwitchCase="'active'">Active</p>
<p *ngSwitchCase="'inactive'">Inactive</p>
<p *ngSwitchDefault>Pending</p>
</div>

Issues with *ngSwitch:

  • Requires multiple *ngSwitchCase directives scattered across the template.

🚀 What Changes with Control Flow Blocks?

Starting with Angular 17, @if, @for, and @switch replace structural directives, improving readability and reducing boilerplate.

🔹 New @if Syntax

@if (user.isAdmin) {
<p>Welcome, admin!</p>
}

Advantages of @if:

  • No need for ng-container: Reduces unnecessary DOM elements.
  • Native support for @else and @else if`:
@if (status === 'active') {
<p>Active</p>
} @else if (status === 'inactive') {
<p>Inactive</p>
} @else {
<p>Pending</p>
}

Previously, handling this required either nested *ngIf directives or ng-template.

🔹 New @for Syntax

<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
}
</ul>

Advantages of @for:

  • More concise: Avoids wrapping elements solely for iteration.
  • Built-in @empty block for handling empty lists:
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>No items found</li>
}
</ul>

Previously, handling empty states required a separate *ngIf condition.

🔹 New @switch Syntax

@switch (status) {
@case ('active') { <p>Active</p> }
@case ('inactive') { <p>Inactive</p> }
@default { <p>Pending</p> }
}

Advantages of @switch:

  • More structured: All cases are contained within a single block, improving readability.

🎯 Scenarios Where Control Flow Blocks Are Superior

The new Control Flow Blocks enable some things that were either difficult or impossible with structural directives:

✅ 1. Inline @else Blocks

Before:

<ng-container *ngIf="condition; else elseBlock">
<p>Condition is true</p>
</ng-container>
<ng-template #elseBlock>
<p>Condition is false</p>
</ng-template>

Now:

@if (condition) {
<p>Condition is true</p>
} @else {
<p>Condition is false</p>
}

Result: Less code, better readability.

✅ 2. Looping Without Extra Elements

Previously, *ngFor required a wrapper element:

<ng-container *ngFor="let item of items">
<p>{{ item }}</p>
</ng-container>

Now, @for does not require a parent element:

@for (item of items) {
<p>{{ item }}</p>
}

Result: Fewer elements in the DOM.

✅ 3. Improved Handling of Empty Lists

Before:

<ul>
<li *ngFor="let item of items">{{ item }}</li>
<li *ngIf="items.length === 0">No items found</li>
</ul>

Now:

<ul>
@for (item of items) {
<li>{{ item }}</li>
} @empty {
<li>No items found</li>
}
</ul>

Result: More straightforward and elegant.

⚡ Conclusion

Control Flow Blocks modernize how Angular templates handle conditional rendering and loops, leading to cleaner, more intuitive, and more performant code.

Key Benefits:

Fewer unnecessary DOM elements

More readable and maintainable templates

Built-in support for @else, @empty, and cleaner @switch blocks

Better developer experience and performance improvements

If you’re upgrading to Angular 17, replacing structural directives with Control Flow Blocks can significantly improve your project’s maintainability and efficiency!

--

--

Felipe Norato
Felipe Norato

Written by Felipe Norato

A person who likes to solve people’s lives using Code and sometimes play Guitar. Lover of TV Shows and Movies, as well as beautiful and performative code.

No responses yet