Introducing Angular’s New Control Flow
With version 17, Angular is introducing a new Control Flow for your applications. You will no longer need to import CommonModule or (if using Standalone components, which will be enabled by default on v17) NgIf, NgFor , or NgSwitch in your apps to be able to use conditionals and loops in your templates. Also, we get the benefit of deferred templates (which are parts of your templates that can be lazy loaded.
After some discussion during the RFC process for this new Control Flow syntax, the Angular team decided (based on community feedback) to go with the @-syntax (as they call it). You can read more about this decision here.
But what would be a blog post of new Angular features without some code, so let’s dive into an example!
Hands on!
Let’s create a new application and see how we can use this new control flow. Start by running the following command on terminal:
npx @angular/cli@17.0.0-next.7 new control-flow-demoBy using npx we avoid installing the pre-release Angular version over our current cli install (which usually is the latest stable release).
This demo will have a Home component which will have a list of names and will have an option to allow users to add new names.
import { Component, signal } from ‘@angular/core’;
import { FormControl, ReactiveFormsModule } from ‘@angular/forms’;
@Component({
selector: ‘app-home’,
standalone: true,
imports: [ReactiveFormsModule],
templateUrl: ‘./home.component.html’,
styleUrls: [‘./home.component.scss’],
})
export class HomeComponent {
showAddName = signal<boolean>(false);
names = signal<string[]>([]);
newName = new FormControl(”);
addName() {
this.names.mutate((names) => names.push(this.newName.value ?? ”));
this.newName.reset();
}
}
Now that we have some logic in our component, we can start working with the template, where we’re going to use the new control flow syntax.
As we want to show a list of names in our component, we are going to use the new @for syntax and as the user is going to enable/disable adding names, we’ll use the new @if syntax for when to show it or not
<div class=”add-new”>
@if (showAddName()) {
<input type=”text” [formControl]=”newName” />
<button (click)=”addName()”>Add name</button>
<button (click)=”showAddName.set(false)”>Close</button>
} @else {
<button (click)=”showAddName.set(true)”>Add a new name</button>
}
</div>
<ul class=”names”>
@for (name of names(); track name) {
<li>
{{name}}
</li>
} @empty {
<li>Name list is empty</li>
}
</ul>
Let’s run the app to see it working!
Kermit drinking a cup of Lipton tea.
Now that we have our app running, lets go back to explain the for and the if syntax:
@if (showAddName()) {
<input type=”text” [formControl]=”newName” />
<button (click)=”addName()”>Add name</button>
<button (click)=”showAddName.set(false)”>Close</button>
} @else {
<button (click)=”showAddName.set(true)”>Add a new name</button>
}
The new if syntax accepts a condition that when true will show the content inside the brackets. And we can add as many, optional, @else if as we require and finally an, optional again, @else for any catch all condition.
And, if we look at the new @for syntax, you can tell that now we’re required to use a track function (so Angular can correctly identify each item that’s added to the DOM from the collection). In this case the item is a string, so we simply set that as the key, but if it was an object (let’s say user) then we could use one property (like id or email)
@for (name of names(); track name) {
<li>
{{name}}
</li>
} @empty {
<li>Name list is empty</li>
}
This was something that we already had in our *ngFor structural directive, but was rarely used, even though it could improve the performance of our app. With the new syntax we’re enforced to use it, throwing an error if it’s not present:
✘ [ERROR] NG5002: @for loop must have a “track” expression [plugin angular-compiler]
src/app/pages/home/home.component.html:11:2:
11 │ @for (name of names()) {
╵ ~~~~~~~~~~~~~~~~~~~~~~~~
And, as you can see, we finally have an option to show content when the array is empty by using @empty so we can finally say good bye to *ngIf=”array.length === 0″.
Bonus benefit!
We will say good by to all those ng-container and ng-template that we used with ngFor and ngIf to handle these kind of conditions.
Kermit wearing a tuxedo walking away from the stage.
Wrapping up
You can tell by now, the Angular team is working really hard to improve not only the performance of our apps but also the Developer eXperience (DX) so both long time Angular devs and newcomers benefit from this updates.
You can find the full code here: https://github.com/eduardoRoth/v17-control-flow
Eduardo is a Senior Software Engineer working at HeroDevs and living in Monterrey, Mexico. Husband, father of three beautiful daughters, loves everything Angular, Ionic and Web related. He’s co-organizer of the Spanish chapter of the Angular Community Meetup, organizer of the Ionic Monterey Meetup, an Ionic Developer Expert, an ngChampion, and on the road to becoming an Angular GDE.
New in Angular — Updated Control Flow was originally published in ngconf on Medium, where people are continuing the conversation by highlighting and responding to this story.