If you've been building Angular apps for any amount of time, you've run into the need to show or hide elements based on some condition  a loading spinner, an error message, a user-specific button. Angular gives you powerful tools to handle all of this directly in your templates. 

In this guide, we'll walk through the classic *ngIf directive, the modern @if block syntax introduced in Angular 17, and how ngClass fits into the picture.



What Is *ngIf and Why Does It Matter?

*ngIf is a structural directive meaning it physically adds or removes elements from the DOM, not just hides them with CSS. That's a meaningful difference. When an element is removed from the DOM, Angular also destroys its component tree, freeing up memory. This makes *ngIf more performant than display: none for large or deeply nested UIs.

<p *ngIf="isLoggedIn">Welcome back, {{ username }}!</p>

If isLoggedIn is false, that <p> tag doesn't exist in the DOM at all  Angular never renders it.

Handling the Else Case

The else branch uses an <ng-template> with a template reference variable. It's a little verbose, but it gets the job done:

<div *ngIf="isLoading; else content">Loading...</div>
<ng-template #content>
  <p>Data loaded successfully!</p>
</ng-template>

The #content reference links the template to the else clause. One thing to watch out for: if that reference doesn't exist or is misspelled, Angular throws an NG01352 error at runtime. Always double-check your template variable names.

Simulating else if With *ngIf

Angular's *ngIf doesn't have a native else if. The workaround is to nest another *ngIf inside an <ng-template>:

<ng-container *ngIf="condition1; then block1 else block2"></ng-container>

<ng-template #block1>Content for condition1</ng-template>
<ng-template #block2>
  <div *ngIf="condition2">Content for condition2</div>
  <div *ngIf="!condition2">Fallback content</div>
</ng-template>

It works, but it gets messy fast. That's exactly the pain point Angular 17 addresses head-on.

Angular 17+ : Enter @if, @else if, and @else

Angular 17 shipped a completely revamped control flow syntax built directly into the compiler. No more *ngIf. No more <ng-template>. Just clean, readable blocks that look and feel like real control flow:

@if (user.role === 'admin') {
  <button>Edit Settings</button>
} @else if (user.role === 'editor') {
  <button>Draft Post</button>
} @else {
  <p>Guest users cannot perform actions.</p>
}

This is a massive improvement in developer experience. Native @else if support alone eliminates a ton of awkward nesting.

Before vs. After

Old Syntax (Angular ≤16) New Syntax (Angular 17+)
*ngIf="isLoggedIn; else loggedOut"+ <ng-template> @if (isLoggedIn) { ... } @else { ... }
No native else if @else if works natively
Requires NgIf import Built into the compiler — no import needed
Verbose, boilerplate-heavy Clean, readable blocks

Type Narrowing Is Now Built In

One underrated benefit of the new syntax is TypeScript-aware type narrowing. Inside an @if block, Angular's compiler knows the type has been checked:

// component.ts
user: User | null = null;

// template
@if (user) {
  <p>{{ user.name }}</p>  <!-- TypeScript knows user is non-null here -->
}

No more ?. safe navigation operators sprinkled everywhere just to avoid null errors.

Pairing with @for and @empty

The new control flow syntax doesn't stop at conditionals. It pairs naturally with @for loops and an @empty block for handling empty lists:

@for (item of items; track item.id) {
  <div>{{ item.name }}</div>
} @empty {
  <p>No items found.</p>
}

Previously, you'd combine *ngFor with an *ngIf check for empty state. Now it's a single, self-contained block.

Dynamic Styling with ngClass

While *ngIf and @if control whether an element exists, ngClass controls how it looks. They complement each other well:

<!-- Apply a single class conditionally -->
<div [ngClass]="{ 'active': isActive }">...</div>

<!-- Apply multiple classes based on different conditions -->
<div [ngClass]="{ 'success': isSuccess, 'error': hasError }">...</div>

A common real-world pattern: use @if to decide if a component renders, and ngClass to handle its visual states once it does.

Common Real-World Use Cases

  • Loading states : Show a spinner while data fetches, swap it for content when ready
  • Error handling : Display alert banners only when an error flag is set
  • Authentication gates : Show Login/Logout buttons based on session state
  • Role-based UI : Render different controls for admins, editors, and viewers using @else if

Best Practices Worth Following

Keep complex logic out of templates. If your condition has more than one or two checks, move it to a getter in the component:

// component.ts
get isUserValid(): boolean {
  return this.user && this.user.isActive;
}

// template
<div *ngIf="isUserValid">...</div>

Use <ng-container> when you need a conditional wrapper that shouldn't add a real DOM node. It's invisible in the rendered output.

Start migrating to @if today. Angular plans to phase out structural directives in favor of the new block syntax. There's an automatic migration command:

ng generate @angular/core:control-flow

This migrates your entire project's *ngIf, *ngFor, and *ngSwitch to the new syntax in one shot.

Troubleshooting: NG01352 Error

If Angular throws NG01352, it can't find the <ng-template> referenced in your *ngIf else clause. The fix is usually one of two things:

  • The #templateName variable is misspelled or missing
  • The template is defined inside another structural directive  Angular can't reach it from there
<!-- This breaks if #missingTemplate doesn't exist -->
<div *ngIf="condition; else missingTemplate"></div>

Quick Reference

Feature *ngIf (≤ Angular 16) @if (Angular 17+)
Basic conditional
Else support ✅ via <ng-template> ✅ natively
Else if ❌ (workaround needed) ✅ natively
Type narrowing
Import required NgIf from @angular/common None
Boilerplate High Minimal

Whether you're maintaining an older codebase or starting fresh, understanding both *ngIf and the new @if syntax gives you the full picture of Angular's conditional rendering story. The new block syntax is clearly the direction Angular is heading  cleaner templates, better type safety, and noticeably faster rendering. Start with the migration command, and you'll be surprised how quick the switch is.

Further Reading:





Instance Of Java

We are here to help you learn! Feel free to leave your comments and suggestions in the comment section. If you have any doubts, use the search box on the right to find answers. Thank you! 😊
«
Next
Newer Post
»
Previous
Older Post

No comments

Leave a Reply

Select Menu