Chapter 4.5โ˜• 16 min read

Old Syntax (*ngIf *ngFor) vs New (@if @for) Migration

Angular 17+ introduced cleaner @ syntax โ€” here's how to migrate from the old * syntax.

01Why Angular Changed the Syntax

Angular 17+ changed how structural directives work โ€” from *ngIf and *ngFor to @if and @for.

"Purana syntax = magic show โ€” samajh nahi aata kya ho raha hai."

"Naya syntax = transparent glass โ€” sab dikhta hai."

Why the change?

  • Hidden complexity: The * prefix expanded to <ng-template> under the hood โ€” beginners had no idea this was happening
  • No else support: *ngIf had no native else โ€” you needed ng-template with #elseRef
  • No @empty: *ngFor had no built-in empty state
  • No @switch: No built-in switch directive existed
  • New @ syntax: Consistent block syntax that matches JavaScript
02@if vs *ngIf โ€” Complete Migration

Old: *ngIf

<!-- Simple condition -->\n<div *ngIf="isVisible">Hello</div>\n<div *ngIf="!isVisible">Bye</div>

New: @if

@if (isVisible) {\n  <div>Hello</div>\n} @else {\n  <div>Bye</div>\n}

Old: *ngIf with ng-template else

<div *ngIf="role === 'admin'; else guestBlock">Admin</div>\n<ng-template #guestBlock><div>Guest</div></ng-template>

New: @if with @else โ€” no reference variables needed!

@if (role === 'admin') {\n  <div>Admin</div>\n} @else {\n  <div>Guest</div>\n}

"Else template reference variable hat gaya โ€” seedha @else likho."

03@for vs *ngFor โ€” Complete Migration

Old: *ngFor

<li *ngFor="let item of items; trackBy: trackFn">\n  {{ item.name }}\n</li>

New: @for

@for (item of items; track item.id) {\n  <li>{{ item.name }}</li>\n} @empty {\n  <li>No items</li>\n}

Key differences:

  • track is REQUIRED โ€” was optional with *ngFor (trackBy). Angular now forces you to think about performance.
  • trackBy function โ†’ direct expression โ€” trackBy: trackFn becomes track item.id. Much simpler!
  • @empty block โ€” replaces *ngIf="items.length === 0" wrapper
  • Index: let i = index in *ngFor vs let i = $index in @for

"Track mandatory hai โ€” Angular force karta hai best practice."

04@switch โ€” Brand New

@switch โ€” this is completely new. There was no built-in switch directive before!

Old way: Had to use chained @if/@else if or the NgSwitch directive with *ngSwitchCase:

// Old: chained @if (before @else if existed)\n@if (status === 'pending') { <p>Waiting</p> }\n@if (status === 'preparing') { <p>Cooking</p> }\n@if (status === 'done') { <p>Complete</p> }\n\n// Old: NgSwitch directive\n<div [ngSwitch]="status">\n  <div *ngSwitchCase="'pending'">Waiting</div>\n  <div *ngSwitchDefault>Unknown</div>\n</div>

New way: @switch

@switch (status) {\n  @case ('pending') { <p>โณ Waiting</p> }\n  @case ('preparing') { <p>๐Ÿณ Cooking</p> }\n  @default { <p>โ“ Unknown</p> }\n}

"Pehle switch ke liye alag library lgani padti thi โ€” ab built-in hai."

05Should You Migrate Existing Code?

Should you migrate your existing Angular code?

  • โœ… New code โ€” Always use new @ syntax. No question.
  • โš ๏ธ Old Angular 16 and below projects โ€” If it works and is stable, don't break it just for syntax.
  • โœ… Angular 17+ upgrade โ€” The Angular CLI has a schematic: ng generate @angular/core:control-flow
  • โš ๏ธ Hybrid codebase โ€” Mixing old and new is fine during migration, but aim for consistency.

"Naya kaam naya syntax, purana kaam chhod do agar chale toh."

The CLI schematic automatically converts *ngIf โ†’ @if and *ngFor โ†’ @for throughout your project. Run it once and review the changes.

Key Takeaways

  • โœ… New @ syntax replaces *ngIf, *ngFor with cleaner block syntax โ€” no hidden ng-template.
  • โœ… @if supports @else and @else if natively โ€” no more ng-template #elseRef.
  • โœ… @for requires track (mandatory) and supports @empty block โ€” better performance by design.
  • โœ… @switch is brand new โ€” no built-in switch existed in older Angular.
  • โœ… Use Angular CLI schematic ng g @angular/core:control-flow to auto-migrate.
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase