Angular Icon Get 73% off the Angular Master bundle

See the bundle then add to cart and your discount is applied.

0 days
00 hours
00 mins
00 secs

Write Angular like a pro. Angular Icon

Follow the ultimate Angular roadmap.

Angular's @if and @else control flow explained

Angular templates just got the best upgrade in years: control flow blocks.

Since the beginning Angular has thrived on this concept of “directives”. We’re starting to see a shift away from that for some of the major parts of Angular - and I love it.

No, before you ask, your custom directives are here to stay. But the built-in Directives like NgIf, Else and Then no longer have a place in this world.

That’s a bold statement. But, it should have been this way from the start. Angular v17 has brought to light such a better experience for developers.

The hype (this time) is real.

So, what is control flow? Control flow is simply where you direct your code based on particular conditionals. You are controlling the flow of your code.

First, let’s assume you’re new to Angular and want to get the latest and greatest syntax.

With a basic component, we want to handle a use-case of toggling some button text based on the working state of our application:

@Component({...})
export class AppComponent implements OnInit {
  user!: User;
  ngOnInit() {
    this.user = {
      name: 'Todd Motto',
      uid: '7H9sjL9aYhz1',
      verified: false
    };
  }
}

And a template:

<div>
  You are logged in
</div>

Our template so far holds no magic, we’ve simply hard-coded “You are logged in”.

So, how can we handle when the user is logged in?

@if syntax

This is where Angular templates have received a massive power-up, we can use JavaScript-like conditional expressions instead of any built-in Directives:

<div>
  @if (user) {
    You are logged in
  }
</div>

This is really smart, and Angular’s powerful type-checking via TypeScript will make this seamless for us too.

Just drop @if () {} inside your template, anywhere, and Angular will do the rest.

But, we’ve not handled the use-case for when there isn’t a user, which might be a great time to introduce an @else statement.

@else syntax

You guessed it, just like JavaScript if/else combination, we can write as follows:

<div>
  @if (user) {
    You are logged in
  } @else {
    You are logged out
  }
</div>

You’ll notice I’ve added a verified property to my user object, which allows us to go a bit deeper and add a nested conditional block:

<div>
  @if (user) {
    @if (user.verified) {
      You are logged in and verified
    } @else {
      You are logged in, but need to verify your email
    }
  } @else {
    You are logged out
  }
</div>

I wanted to demonstrate the power of nesting these conditional @if and @else blocks, but we can also take this one-step further if we only assume all logged in users are also verified:

<div>
  @if (user?.verified) {
    You are verified
  } @else {
    You are logged out
  }
</div>

You’ll notice I’m using the ? after the object we are checking against. This is called “Optional Chaining” in TypeScript and will check against null or undefined values for us.

@if / @else if / @else

We can also further use @if and @else statements to created if/else if/else statements:

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

🚀 When you write else if in JavaScript, you’re actually nested an if statement inside an else statement - it’s just written on the same line. The same applies with Angular, but as we’re already declaring a new block with the @ symbol, we don’t need to use it again with @else if.

@if and Observables

“But what about Observables?!” I hear you ask. Fear not, this is seamless as well.

It’s common practice to ‘unwrap’ your Observables at a top-level in the component to make it available throughout the template, we can adjust our template to handle an Observable via the AsyncPipe and use the as X syntax to expand it as a variable for us to reference:

<div>
  @if (user$ | async; as user) {
    @if (user.verified) {
      You are logged in and verified
    } @else {
      You are logged in, but need to verify your email
    }
  } @else {
    You are logged out
  }
</div>

Of course, this means we’ll now need to supply Observable state to our component class. In a standalone component world, we’ll also need to make sure we import the AsyncPipe and add it to our list of imports too:

@Component({
  standalone: true,
  imports: [AsyncPipe],
  template: `...`
})
export class AppComponent implements OnInit {
  user$!: Observable<User>;
  ngOnInit() {
    this.user$ = of({
      name: 'Todd Motto',
      uid: '7H9sjL9aYhz1',
      verified: false
    });
  }
}

It’s much more likely you’ll fetch this data from the server and pipe it through a service though, but here’s how you’d adopt an Observable approach to let the template subscribe and unwrap it for you.

Legacy: NgIf and Else statements

Before all of this, we’d have to deal with creating new elements, or virtual elements (which was my go-to weapon of choice using <ng-container>), to handle all of the above, which just littered the template with far too many elements.

This made is quite challenging to actually see what was happening.

An example using <ng-container> alongside <ng-template> and an Observable approach prior to this new @if and @else control flow syntax:

<div>
  <ng-container *ngIf="user$ | async as user">
    <ng-container *ngIf="user.verified; else notVerified">
      You are logged in and verified
    </ng-container>
    <ng-template #notVerified>
      You are logged in, but need to verify your email
    </ng-template>
    You are logged out
  </ng-container>
</div>

Confusing, right? Definitely. I’m just glad we don’t need tto use <ng-template> to handle else statements anymore, as this was probably the worst part of the NgIf syntax.

This is a huge improvement, but that’s not to say you have to start your day tomorrow by refactoring your entire codebase to use this new sytnax, but it’s very easily done if you do.

What’s more, you can incrementally do this, one template at a time. There are no special imports you need and it’s available for you to use today in Angular v17 and beyond.

For more, drop by my Angular courses and I’m sure you’ll learn a thing or three.

Happy control flowing, dear Angular friend.

Learn Angular the right way.

The most complete guide to learning Angular ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover