Sintaks Control Flow Angular di 2026: @if, @for, @switch dan Pertanyaan Wawancara
Pelajari sintaks control flow Angular (@if, @for, @switch) yang menggantikan directive struktural. Panduan lengkap dengan contoh kode, tips migrasi, dan pertanyaan wawancara teknis.

Sintaks control flow Angular (@if, @for, @switch) menggantikan directive struktural *ngIf, *ngFor, dan *ngSwitch yang telah mendominasi template Angular selama bertahun-tahun. Diperkenalkan di Angular 17, stabil sejak Angular 18, dan menjadi default di Angular 22, sintaks berbasis blok ini membawa template lebih dekat ke konstruksi pemrograman standar sekaligus memungkinkan optimasi performa yang lebih baik.
Jalankan ng generate @angular/core:control-flow untuk melakukan migrasi otomatis dari directive struktural ke sintaks control flow baru. Kedua sintaks dapat hidup berdampingan selama migrasi, namun ngIf, ngFor, dan ngSwitch sudah deprecated sejak Angular 19.
Mengapa Angular Mengganti Directive Struktural dengan Sintaks Blok
Directive struktural memerlukan import CommonModule, menggunakan mikrosintaks yang berbeda dari JavaScript, dan memaksa developer untuk membungkus konten dalam ng-template untuk kondisi yang kompleks. Sintaks control flow baru menyelesaikan masalah-masalah ini:
- Tidak perlu import:
@if,@for, dan@switchsudah built-in di framework - Sintaks mirip JavaScript: kondisi dan loop terbaca seperti kode standar
- Dukungan native
@else: tidak perlu lagi referensing-templateuntuk branch else - Tree-shaking lebih baik: blok control flow yang tidak digunakan tidak berdampak pada ukuran bundle
Dokumentasi Angular merekomendasikan untuk mengadopsi sepenuhnya sintaks blok di semua proyek baru, dan melakukan migrasi codebase yang ada secara bertahap.
@if: Conditional Rendering Tanpa ng-template
Blok @if merender konten secara kondisional berdasarkan ekspresi yang truthy. Berbeda dengan *ngIf, blok ini mendukung branch @else if dan @else secara langsung:
import { Component, input } from '@angular/core';
@Component({
selector: 'app-user-status',
template: `
@if (user().role === 'admin') {
<app-admin-panel />
} @else if (user().role === 'editor') {
<app-editor-panel />
} @else {
<app-viewer-panel />
}
`
})
export class UserStatusComponent {
user = input.required<{ role: string }>();
}Blok @if juga mendukung aliasing variabel dengan keyword as, yang mengekstrak nilai dari ekspresi bersarang:
<!-- Menghindari akses properti berulang -->
@if (user().profile?.settings?.theme; as theme) {
<p>Tema saat ini: {{ theme }}</p>
}Pola ini sangat berguna ketika bekerja dengan data async atau objek yang deeply nested, karena variabel yang di-alias hanya terdefinisi ketika kondisi bernilai truthy.
@for: Iterasi dengan Track Expression yang Wajib
Blok @for melakukan iterasi pada iterable JavaScript apa pun, dengan optimasi untuk array. Berbeda dengan *ngFor, blok ini memerlukan ekspresi track:
import { Component, input } from '@angular/core';
interface Product {
id: string;
name: string;
price: number;
}
@Component({
selector: 'app-product-list',
template: `
@for (product of products(); track product.id) {
<app-product-card [product]="product" />
} @empty {
<p>Tidak ada produk tersedia</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}Ekspresi track memberitahu Angular cara mengidentifikasi setiap item di setiap re-render. Memilih properti tracking yang tepat berdampak langsung pada performa:
| Ekspresi Track | Kasus Penggunaan | Dampak Performa |
|---|---|---|
track item.id | Item dengan identifier unik | Optimal: update DOM minimal |
track $index | Daftar statis yang tidak pernah diurutkan ulang | Dapat diterima: re-render penuh saat pengurutan ulang |
track item | Tracking referensi | Buruk: referensi baru = node DOM baru |
Variabel Kontekstual dalam Blok @for
Angular menyediakan variabel implisit di dalam blok @for yang mengekspos metadata iterasi:
@for (item of items(); track item.id; let i = $index, isLast = $last) {
<li class="item" [class.last]="isLast">
{{ i + 1 }}. {{ item.name }}
</li>
}Variabel kontekstual yang tersedia:
$index: posisi berbasis nol$count: jumlah total item$first,$last: flag boolean untuk item pertama/terakhir$even,$odd: flag boolean berdasarkan paritas index
Siap menguasai wawancara Angular Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
@switch: Conditional Branching yang Type-Safe
Blok @switch menyediakan pattern matching yang exhaustive dengan perbandingan strict equality (===):
import { Component, input } from '@angular/core';
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';
@Component({
selector: 'app-status-badge',
template: `
@switch (status()) {
@case ('pending') {
<span class="badge badge-gray">Menunggu</span>
}
@case ('processing') {
<span class="badge badge-blue">Diproses</span>
}
@case ('shipped') {
<span class="badge badge-yellow">Dikirim</span>
}
@case ('delivered') {
<span class="badge badge-green">Terkirim</span>
}
}
`
})
export class StatusBadgeComponent {
status = input.required<OrderStatus>();
}Berbeda dengan switch JavaScript, @switch Angular tidak memiliki perilaku fallthrough. Beberapa kondisi yang menargetkan blok yang sama memerlukan statement @case berurutan:
@switch (userRole()) {
@case ('admin')
@case ('superadmin') {
<app-admin-dashboard />
}
@case ('editor')
@case ('reviewer') {
<app-editor-dashboard />
}
@default {
<app-viewer-dashboard />
}
}Pengecekan Tipe Exhaustive dengan @default never
Angular 22 mendukung pengecekan exhaustiveness pada waktu kompilasi. Menggunakan @default never; mendeklarasikan bahwa tidak ada kasus tersisa yang seharusnya ada:
type Theme = 'light' | 'dark' | 'system';
// Error kompilasi jika ada nilai Theme yang hilang dari blok @case
@switch (theme()) {
@case ('light') { /* ... */ }
@case ('dark') { /* ... */ }
@case ('system') { /* ... */ }
@default never;
}Menambahkan nilai baru ke union Theme akan memicu error kompilasi, memaksa developer untuk menangani semua kasus.
Sintaks Control Flow dan Integrasi Angular Signals
Blok control flow terintegrasi dengan mulus dengan Angular Signals, memungkinkan reaktivitas yang fine-grained:
import { Component, computed, signal } from '@angular/core';
@Component({
selector: 'app-dashboard',
template: `
@if (isLoading()) {
<app-skeleton />
} @else if (hasError()) {
<app-error [message]="errorMessage()" />
} @else {
@for (item of filteredItems(); track item.id) {
<app-item-card [item]="item" />
} @empty {
<p>Tidak ada item yang cocok dengan filter</p>
}
}
`
})
export class DashboardComponent {
items = signal<Item[]>([]);
filter = signal('');
isLoading = signal(true);
hasError = signal(false);
errorMessage = signal('');
// Computed signal hanya menghitung ulang ketika dependencies berubah
filteredItems = computed(() =>
this.items().filter(item =>
item.name.toLowerCase().includes(this.filter().toLowerCase())
)
);
}Ketika signal diperbarui, Angular hanya mengevaluasi ulang blok control flow yang terpengaruh. Dikombinasikan dengan deteksi perubahan zoneless Angular, ini memungkinkan rendering yang sangat teroptimasi.
Pertanyaan Wawancara Umum tentang Control Flow Angular
Wawancara teknis sering menguji pemahaman tentang sintaks control flow, terutama perbedaan dari directive struktural.
Pertanyaan 1: Mengapa track wajib di @for?
Ekspresi track menyediakan Angular dengan identitas yang stabil untuk setiap item. Tanpa itu, Angular tidak dapat secara efisien menentukan node DOM mana yang harus dibuat, diperbarui, atau dihancurkan ketika koleksi berubah. Mewajibkan track memaksa developer untuk membuat keputusan eksplisit tentang identitas, menghindari jebakan performa dari tracking referensi implisit.
Pertanyaan 2: Bagaimana @if berbeda dari *ngIf dengan async pipe?
Keduanya dapat menangani observable, tetapi @if dengan signals menyediakan akses sinkron ke nilai:
// Dengan *ngIf dan async pipe (legacy)
<div *ngIf="user$ | async as user">{{ user.name }}</div>
// Dengan @if dan signals (modern)
@if (user(); as user) {
<div>{{ user.name }}</div>
}Pendekatan signal menghindari manajemen subscription dan terintegrasi lebih baik dengan deteksi perubahan Angular.
Pertanyaan 3: Bisakah @switch menggantikan rantai @if/@else if yang kompleks?
@switch sebaiknya digunakan ketika membandingkan ekspresi tunggal dengan beberapa nilai diskret. Untuk kondisi boolean kompleks yang melibatkan ekspresi berbeda, @if/@else if tetap lebih sesuai:
<!-- Gunakan @switch untuk ekspresi tunggal, banyak nilai -->
@switch (status()) {
@case ('active') { ... }
@case ('inactive') { ... }
}
<!-- Gunakan @if untuk banyak ekspresi -->
@if (isAdmin() && hasPermission('write')) {
...
} @else if (isEditor()) {
...
}Pertanyaan 4: Apa yang terjadi pada @for ketika koleksi kosong?
Ketika iterable tidak berisi item, Angular melewatkan konten @for sepenuhnya. Blok @empty opsional merender konten fallback dalam kasus ini. Tanpa @empty, tidak ada yang dirender, yang berbeda dari beberapa framework yang merender container kosong.
Migrasi dari Directive Struktural ke Control Flow
Angular CLI menyediakan skematik migrasi otomatis:
# Migrasi seluruh proyek
ng generate @angular/core:control-flow
# Migrasi direktori tertentu
ng generate @angular/core:control-flow --path=src/app/featuresSkematik menangani sebagian besar transformasi secara otomatis, tetapi tinjau output untuk kasus khusus:
| Directive Struktural | Equivalent Control Flow |
|---|---|
*ngIf="condition" | @if (condition) { } |
*ngIf="condition; else elseBlock" | @if (condition) { } @else { } |
*ngFor="let item of items" | @for (item of items; track item) { } |
*ngFor="let item of items; index as i" | @for (item of items; track item; let i = $index) { } |
[ngSwitch] + *ngSwitchCase | @switch + @case |
Setelah migrasi, hapus import CommonModule dari standalone components yang tidak lagi menggunakan directive struktural.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Poin Penting untuk Sintaks Control Flow Angular
- Sintaks control flow Angular (
@if,@for,@switch) adalah pendekatan yang direkomendasikan sejak Angular 19, menggantikan directive struktural - Ekspresi
trackdi@forwajib: gunakan identifier unik sepertiitem.iduntuk performa optimal, hindaritrack itemyang menyebabkan re-render berbasis referensi @ifmendukung branch native@else ifdan@elsetanpang-template, dan keywordasmembuat alias nilai truthy untuk penggunaan ulang@switchmenggunakan strict equality dan tidak memiliki fallthrough: statement@caseberurutan menargetkan blok yang sama, dan@default never;memungkinkan pengecekan tipe exhaustive- Blok control flow terintegrasi dengan Signals untuk reaktivitas fine-grained: hanya blok yang terpengaruh yang di-render ulang ketika signals diperbarui
- Jalankan
ng generate @angular/core:control-flowuntuk melakukan migrasi template yang ada secara otomatis
Bisakah kamu menemukan bug di Angular?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 3 September 2026
Tag
Bagikan
Artikel terkait

Dependency Injection Lanjutan di Angular 2026: Providers, Tokens, dan Pertanyaan Interview
Pelajari sistem dependency injection Angular secara mendalam termasuk strategi provider, InjectionToken, injector hierarkis, dan pertanyaan interview umum untuk developer Angular berpengalaman.

Angular Signals dan Computed di 2026: Reaktivitas Fine-Grained dan Pertanyaan Interview
Pelajari Angular Signals dan computed signals untuk reaktivitas fine-grained di Angular 20+. Panduan lengkap mencakup signal primitives, linkedSignal, interoperabilitas RxJS, dan pertanyaan interview teknis.

Pertanyaan wawancara Angular 19: Signals, SSR, dan konsep wajib diketahui
Pertanyaan wawancara Angular 19 yang paling umum: Signals, hidrasi inkremental, zoneless change detection, dan API reaktif baru lengkap dengan contoh kode dan jawaban yang diharapkan.