Angular 17: A Comprehensive Guide to New Control Flow
A journey of discovering the new features of Angular 17
Introduction
Hey there, developers! Remember last time our exploration journey in Angular 17’s new features. Well, guess what? it has officially landed on November 8th, bringing a heap of fresh updates with it.
In our previous article, we talked about one of the new features “Deferred Loading”, and how it can lazy load block’s content. But today, we’re switching gears, as we will be diving headfirst into something equally exciting: The improved control flow syntax in Angular 17.
Let us unravel how these new control flow features make coding easier, clearer, and more efficient for us.
You can access all the source code examples featured in this article here.
Conditional Statements
In the provided first example, the traditional *ngIf directive is utilized. Initially, a checkbox is created and bound to the isCompleted variable. It starts unchecked, indicating that the task has not been completed yet. Therefore, within our ngIf statement, the content reflects this status with the message ‘Ouch! The task wasn’t completed’. However, once we check the checkbox, the else content is rendered, displaying the affirmation “Congratulations! Task completed.”
<input [(ngModel)]="isCompleted" type="checkbox" /> Check when you complete the task
<div *ngIf="isCompleted; else notCompleted">
<p>Congratulations! task completed.</p>
</div>
<ng-template #notCompleted>
<p>Ouch! task wasn't completed.</p>
</ng-template>
Easy, right? Not quite yet. Fortunately , the Angular team has made this process a lot easier through the use of this very new, self-explanatory syntax.
@if (isCompleted) {
<p>Congratulations! task completed.</p>
}
@else {
<p>Ouch! task wasn't completed.</p>
}
For Loop
This particular feature stands out as one of my most favorable updates, simplifying the usage of for-loops for developers in contrast to the old *ngFor. The Angular team has also highlighted that using the new for loop imporves the rendering times as well.
Now, let’s delve into this functionality through a practical demonstration. Considering we want to loop through a task object array, previously it has been done this way
<ul *ngFor="let task of tasks; trackBy: trackById">
<strong>{{task.name}}</strong>
</ul>
See that sneaky trackBy? In fact, using an ngFor* directive without it frequently arising performance issues — To put in more clearer way: without this ngFor* , your app might just decide to take a coffee break while struggling to keep up! Therefor, utilizing trackBy becomes essential for optimizing the diffing performance.
trackById = (index: number, task: Task): string => {
return task.id.toString();
};
Now comes the new control flow for loop with Angular 17.
<ul>
@for (task of tasks; track task.id; let index = $index, first = $first, last = $last, even = $even, odd = $odd, count = $count) {
Total count {{count}}
<li>
<strong>{{task.name}}</strong>
- index {{index}}
- is it first? {{first}}
- is it last? {{last}}
- is it even? {{even}}
- is it odd? {{odd}}
</li>
}
@empty {
<span>Task list is empty</span>
}
</ul>
Let’s decouple it:
- Notice the track task.id? It links array items to DOM views as trackById previously, ensuring minimal DOM operations during collection changes with clear item identity. — check the angular documentation for more.
$count
Number of items in the iterated array$index
Index of the current row$first
Whether the current row is the first row$last
Whether the current row is the last row$even
Whether the current row index is even$odd
Whether the current row index is odd@empty
Block content to be rendered if the array is empty
Switch case
Taking this example for the switch-case, there are several radio buttons — which could be visualised on the github code here. Each radio button contains a value. When checked, they update the value of the fruit to the selected option. Accompanying this, a switch-case structure is utilized to display the value of the selected fruits.
<div [ngSwitch]="fruit">
<span *ngSwitchCase="'apple'">Apple</span>
<span *ngSwitchCase="'orange'">Orange</span>
<span *ngSwitchCase="'watermelon'">Watermelon</span>
<span *ngSwitchDefault>No fruit has been chosen.</span>
</div>
In Angular 17, the new syntax looks like this
<div>
@switch (fruit) {
@case ('apple') { <span>Apple</span> }
@case ('orange') { <span>Orange</span> }
@case ('watermelon') { <span>Watermelon</span> }
@default { <span>No fruit has been chosen.</span> }
}
</div>
My 2-cents
In my humble and obviously correct opinion, the new syntax is a breath of fresh air as compared to the old one, and requires less mental gymnastics to understand what’s going on even for experienced Angular devs, let alone newbies. Subjectivity aside, let’s collectively admit it resembles the comforting syntax you’d stumble upon while tinkering with Typescript or Javascript (or practically any language, really).
Conclusion
In this article, I’ve explained how the new control features in Angular 17 work. Also, we walked through how to create conditional blocks, loops, and switch cases using this updated syntax. Hope you find it helpful!
In the first part of this series, I talked about the new deferred loading feature in Angular 17. It explains how to set conditions to load and show content in these blocks.
That’s it from me, and until next time; keep on learning, and happy coding.