Why I Stopped Using ngIf and ngFor in Angular



This content originally appeared on DEV Community and was authored by Naji Louis

I’ve been using Angular for quite some time, and like many developers, I got used to writing *ngIf, *ngFor, and ngSwitch in almost every component. They worked fine until Angular introduced a new syntax that completely changed how I write templates.

I’m talking about the new control flow syntax:
@if, @else, @for, @let, @switch, @case, and @default.

At first, I didn’t pay much attention. But after giving them a try, I quickly realized how much cleaner, simpler, and more natural my templates became.
Here’s why I stopped using the old syntax and why you might want to as well.

The Problem with the Old Syntax

The old *ngIf, *ngFor, and ngSwitch directives worked well, but they had a few downsides:

  • The asterisks * looked strange to new developers.

  • You often needed extra <ng-container> or <ng-template> tags.

  • Nested conditions and loops were harder to read.

Angular’s new syntax fixes all of that. It’s built directly into the template engine, meaning no more directives — just clean, readable control flow.

@if and @else
The new @if syntax replaces *ngIf and feels much closer to regular JavaScript logic.

Before:

<div *ngIf="isLoggedIn; else guestPart">
  Welcome back!
</div>

<ng-template #guestPart>
  Please log in.
</ng-template>

Now:

@if (isLoggedIn) {
  <div>Welcome back!</div>
} @else {
  <div>Please log in.</div>
}

✅ Easier to read
✅ No blocks or template references
✅ Perfect for nesting conditions

@for
The classic *ngFor still works, but @for feels cleaner and reads more like plain JavaScript.

Before:

<ul>
  <li *ngFor="let user of users; trackBy: trackById">
    {{ user.name }}
  </li>
</ul>

Now:

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

✅ Simpler syntax (track instead of trackBy)
✅ No asterisk confusion
✅ Easier to reason about

@let
Sometimes you need to store a local variable in your template.
@let makes that super easy.

Before:

<ng-container *ngIf="user as u">
  <p>Hello {{ u.name }}</p>
</ng-container>

Now:

@let u = user;
<p>Hello {{ u.name }}</p>

✅ Cleaner variable handling
✅ Works outside @if blocks
✅ Makes templates easier to follow

@switch, @case, and @default
The new @switch syntax replaces ngSwitch and feels just like a real switch statement in JavaScript.

Before:

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

Now:

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

✅ More readable
✅ No extra attributes
✅ Matches JavaScript logic perfectly

How to Start Using It

You’ll need Angular 17 or newer to use this new syntax.
If you’re upgrading, just run:

ng update @angular/core@latest @angular/cli@latest

No extra setup or imports needed — it’s ready out of the box.

Final Thoughts

After switching to the new syntax, my templates feel much cleaner and easier to maintain.
I don’t need to wrap everything in containers or remember special * rules anymore.

If you’ve been using Angular for a while, try replacing a few *ngIf or *ngFor blocks with the new syntax and you’ll instantly see the difference.

Sometimes small changes make a big impact and this one definitely does.


This content originally appeared on DEV Community and was authored by Naji Louis