A fresh approach to writing conditionals, alternate branches, switch statements, and iterations within Angular templates!

emoji_objects emoji_objects emoji_objects
Kevin Kreuzer

Kevin Kreuzer

@nivekcode

Oct 24, 2023

5 min read

Angular Control Flow
share

(📸 by Javier Martínez)

The upcoming release of Angular 17 brings a fresh template capability called control flow. This approach redefines how developers write if statements, if-else statements, switch-case statements, and for loops.

On top of that, Angular 17 is set to ship “Deferable Views,” a compelling new option that we’ll explore in a separate post. Join our newsletter so you don't miss it!{:target="_blank"}

Let's look ahead at Angular's evolution and see how we'll structure our if-else, switch-case, and for loops. Our starting point is the simplest and most essential case: the basic if condition.

The @if conditions

Previously, Angular enabled simple if statements via the NgIf directive.

<div *ngIf="condition">Content</div>

Compiling this code required the NgIf directive to be included in the component’s imports array. Here is the full component structure that would be used.

@Component({
  standalone: true,
  template: `<div *ngIf="condition">Content</div>`,
  imports: [NgIf],
})
export class MyComponent {}

Now it’s time to see how Angular 17’s brand-new control flow syntax lets us rework this same code in a more dynamic way.

@if (condition) {
  <div>Content</div>
}

The syntax here looks nearly identical to a standard JavaScript function, with the sole exception being the @ prefix preceding the if keyword.

That was straightforward. Now, how do we handle an if-else scenario?

If this syntax feels new, simply consider how you would structure an if/else in vanilla JavaScript, then place an @ symbol before each keyword.

@if (streamingService === 'Netflix'){
  <div>Peaky Blinders</div>
} @else {
  <div>Ted Lasso</div>
}

It really is that simple. You simply add an @ before both if and else, and then have your functions return templates rather than printing logs.

Alright, an if-else block—what’s the big deal? Right now, replicating this behavior requires the code below.

<div *ngIf="streamingService === 'Netflix'; else appleTVShow">
  Peaky Blinders
</div>

<ng-template #appleTVShow>
  <div>Ted Lasso</div>
</ng-template>

In my view, the new syntax significantly enhances clarity. On top of that, it is far simpler to explain, given its strong resemblance to plain JavaScript.

What is your take? Which option do you find clearer? Share your thoughts in the comment section below.

That covers everything about control flow and if-else—now let's move on to switch-case statements.

The @switch case

The Switch-Case statement lets you assess an expression and run distinct code sections depending on the case that matches, proving to be a valuable approach for managing various branching scenarios.

With the current Angular release, constructing a switch-case statement required adding these directives to our components or modules imports array: NgSwitch, NgSwitchCase, and NgSwitchDefault. Consequently, the HTML structure appeared as follows:

<div [ngSwitch]="streamingService">
  <div *ngSwitchCase="'AppleTV'">Ted Lasso</div>
  <div *ngSwitchCase="'Disney+'">Mandalorian</div>
  <div *ngSwitchDefault>Peaky Blinders</div>
</div>

Let’s transition this to the updated control flow syntax.

@switch(streamingService) { 
  @case ('Disney+') {
    <div>'Mandalorian'</div>
  } @case ('AppleTV') {
    <div>'Ted Lasso'</div>
  } @default {
    <div>'Peaky Blinders'</div>
  }
}

Once more, this syntax mirrors JavaScript but swaps : for curly braces when writing case statements.

Excellent—who's eager to tackle loops next?

The @for loops

Nearly every app relies on loops as essential constructs for handling arrays and datasets. In its current form, Angular gives us the ngFor directive for this purpose.

<ul>
  <li *ngFor="let streamingService of streamingServices">
    {{streamingService}}
  </li>
</ul>

Here's how a loop of this kind is implemented in an Angular template with the newly introduced control flow syntax.

<ul>
  @for (streamingService of streamingServices; track streamingService) {
    <li>{{streamingService}}</li>
  }
</ul>

Several differences stand out here. For one, the let keyword no longer appears before the variable declaration; for another, a track function is now introduced.

A superior "track" alternative

Does track sound familiar? It likely brings to mind the optional trackBy function that we’ve relied on with ngFor up to this point.

Within Angular, the trackBy function pairs with the ngFor directive to streamline list rendering. It tags each list item with a distinct identifier, enabling Angular to efficiently refresh or adjust individual entries without rerendering the full list. The result is better performance, particularly for extensive lists.

☝️ Seen lag with large lists before? That might stem from omitting the trackBy function. Research into performance conducted by the Angular team uncovered that NgFor iterating over immutable data with no trackBy ranks among the most frequent sources of performance slowdowns in Angular apps.

Given the potential for performance degradation, the track function is now mandatory for for loops.

What’s great about track is that the full expression can be written directly inline, making a dedicated function within the template unnecessary.

@for (product of products; track product.id) { 
 {{ product.title }} 
}

The trackBy function can still be called using track, primarily to support migration scenarios.

@for (product of products; track productId($index, product)) { 
  {{ product.title}} 
}

Implicit variables

Within the updated control flow syntax, these variables become accessible inside a for row view.

Angular control flow syntax variables

In order to read those values, the let keyword must be used, which lets us bind them to a variable name we pick.

<ul>
  @for (service of streamingServices; track service; let i =
    $index; let first = $first; let last = $last; let even = $even; let odd = $odd
  ) {
    <li>{{i}} {{first}} {{last}} {{even}} {{odd}}</li>
  }
</ul>

Pretty exciting, right? Yet there’s even more on offer—an @empty block is the latest addition.

Empty block

The @empty block enables us to show an element even if the list contains no items.

Imagine we’ve got a list showing every streaming service the user subscribes to. When the user subscribes to nothing, a div with a message appears. That scenario is exactly where the @empty block fits in.

@for (streamingService of streamingServices; track stramingService) {
  <div>{{ streamingService }}</div>
} @placeholder {
  <div>No streaming services available</div>
}

Automated migration

If you're someone who, much like me, appreciates the cleaner, more legible syntax, you may be tempted to spruce up your entire codebase with this modern control flow style. Yet that might involve considerable effort, given that ngIf and ngFor directives are sprinkled throughout your whole project.

However, there’s no need for concern — Angular ships with a powerful migration tool that can convert our app over to the new control flow syntax.

ng g @angular/core:control-flow

To wrap up, the revised control flow syntax brings more than just cleaner code — it adds a layer of intuitiveness and grace to the way we write. I’m genuinely impressed by these updates and see them as a meaningful leap forward, helping us keep our codebases tidy and streamlined.

We’d love to hear what you think, so drop your feedback in the comments — your take on this exciting shift matters to us. Happy coding!

Further resources

For those looking to dive deeper into the standout control flow feature, head over to my Stream VOD and give the intro video a spin. It’s a great, lighthearted way to get the essentials on everything control flow delivers.

Like what you see in the code preview? Check out our fresh theme plugin

Skol - the definitive IDE theme

Skol - the ultimate IDE theme

Bring the aurora borealis experience directly into your development environment. This clean yet robust dark theme not only looks polished but also reduces eye strain.

Create more intuitive interfaces by combining Angular with AI

Learning Angular Through AI-Powered Video

Angular + AI Video Course

A practical workshop on bringing AI into your Angular projects, showing how Hash Brown can help craft responsive and smart user interfaces.

Walk through real examples covering streaming conversations, tool invocation, generative UIs, and structured responses — all explained incrementally.

If you find this useful and are curious about keeping your Angular app maintainable over the long haul, there's more to explore.

Angular Enterprise Architecture eBook

Angular Enterprise Architecture eBook

Discover the approach to structuring both greenfield and established enterprise-scale Angular projects using robust, tool-supported automated architecture validation.

By doing so, you guarantee that your codebase remains easy to maintain, ready for growth, and capable of sustaining fast feature delivery across the entire lifespan of the application!

Are you finding this useful and eager to dive deep into Angular's innovative Signal Forms?

Angular Signal Forms: Comprehensive Practitioner Workshop

Angular Signal Forms: Hands-On Masterclass

Dive into Angular's latest Signal-Forms across 12 step-by-step chapters, blending theory with practical exercises.

Explore core form concepts, validation logic, bespoke controls, nested forms, and transition tactics—and much more!

Win win deal illustration

Never miss a story
from the blog again

Join the Angular Experts Content Updates & News mailing list, and we will let you know the moment a fresh post about Angular, Ngrx, RxJs, or any other compelling Frontend topic goes live.

Your email stays private — rest assured, unsubscribing is always just one click away!

Occasionally, you might receive extra promotional material; find out more by reading our Privacy policy.

Join the discussion

Feel free to post your questions, insights, or share your unique point of view on the subject

You might also like

Discover more related content, such as Modern Angular , by browsing these additional posts from the Angular Experts team!

Angular Signal Forms: Custom Controls Without ControlValueAccessor

Angular Signal Forms: Custom Controls Without ControlValueAccessor

Build reusable Angular custom controls with FormValueControl, model(), touch events, and schema-driven validation—without writing a ControlValueAccessor.

emoji_objects emoji_objects emoji_objects
Kevin Kreuzer

Kevin Kreuzer

@nivekcode

Aug 12, 2026

7 min read

Angular Signal Forms: The Missing Create/Edit Pattern

Angular Signal Forms: The Missing Create/Edit Pattern

Learn a practical Angular Signal Forms pattern for create and edit flows, with route-based mode, edit data loading, linkedSignal prefilling, submit branching, and validation context.

emoji_objects emoji_objects emoji_objects
Kevin Kreuzer

Kevin Kreuzer

@nivekcode

Aug 1, 2026

6 min read

Angular Signal Forms Essentials

Angular Signal Forms Essentials

Understand the core concepts behind modern Angular Forms. Learn how to create Signal Forms, wire them up in templates, use built-in and custom validators, handle cross-field validation, submit forms, and more.

emoji_objects emoji_objects emoji_objects
Kevin Kreuzer

Kevin Kreuzer

@nivekcode

Feb 14, 2026

12 min read

Empower your team with our extensive experience

Angular Experts have accumulated years of consulting with both enterprises and startups, delivering workshops and tutorials, and sustaining a rich ecosystem of open source resources. Our pride in modern front-end expertise is immense, and we are eager to see your business thrive with our support.