Old Syntax (*ngIf *ngFor) vs New (@if @for) Migration
Angular 17+ introduced cleaner @ syntax โ here's how to migrate from the old * 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:
*ngIfhad no native else โ you needed ng-template with #elseRef - No @empty:
*ngForhad no built-in empty state - No @switch: No built-in switch directive existed
- New @ syntax: Consistent block syntax that matches JavaScript
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."
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: trackFnbecomestrack item.id. Much simpler! - @empty block โ replaces
*ngIf="items.length === 0"wrapper - Index:
let i = indexin *ngFor vslet i = $indexin @for
"Track mandatory hai โ Angular force karta hai best practice."
@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."
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.
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login