Control flow adalah blok di template yang memutuskan bagian mana yang dirender: @if memilih ditampilkan atau gak, @for mengulang satu bagian untuk tiap isi array, dan @switch memilih satu dari beberapa kemungkinan. Bayangin papan menu Martabak Bang Jali. "Kalau stoknya nol, tulis Habis" itu @if. "Tulis satu baris untuk tiap menu" itu @for. Lampu status pesanan di kasir, yang menyala di salah satu dari diproses, dikirim, atau sampai, itu @switch.
Ketiganya bagian dari template sejak Angular 17, jadi gak perlu import apa pun, dan menggantikan *ngIf, *ngFor, dan [ngSwitch] dari pelajaran sebelumnya. Contoh di sini tetap menulis standalone: true, bentuk yang masih banyak ditemui di kode lama; sejak Angular 19 baris itu bawaan, juga di editor latihan (Angular 22).
🧪 Tebakan cepat: Tiap baris menu punya kotak catatan. Kamu mengetik "tanpa daun bawang" di baris Martabak Manis Cokelat Keju, lalu urutan menunya dibalik. Kalau
@for-nya ditulis dengantrack $index, catatan itu sekarang ada di baris martabak yang mana? Jawabannya ada di bagian "track: cara Angular mengenali baris".
@if, @else if, @else
import { Component } from '@angular/core'
@Component({
selector: 'app-root',
standalone: true,
template: `
<ul>
@for (m of menu; track m.id) {
<li>
{{ m.nama }}
@if (m.stok === 0) {
<b>Habis</b>
} @else if (m.stok < 5) {
<b>Sisa {{ m.stok }}</b>
} @else {
<b>Tersedia</b>
}
</li>
}
</ul>
`,
})
export class App {
menu = [
{ id: 1, nama: 'Martabak Manis Cokelat Keju', stok: 4 },
{ id: 2, nama: 'Martabak Telur Spesial', stok: 6 },
{ id: 3, nama: 'Terang Bulan Pandan', stok: 0 },
]
}
| Menu | stok |
Cabang yang jalan | Tampil |
|---|---|---|---|
| Martabak Manis Cokelat Keju | 4 | @else if (m.stok < 5) |
Sisa 4 |
| Martabak Telur Spesial | 6 | @else |
Tersedia |
| Terang Bulan Pandan | 0 | @if (m.stok === 0) |
Habis |
- Syaratnya ditulis di dalam kurung, isinya di dalam kurung kurawal. Angular mencoba cabang dari atas, dan cuma cabang pertama yang benar yang dirender.
- Cabang yang gak terpilih gak disembunyikan, tapi gak ada di DOM sama sekali.
@elseharus menempel langsung sesudah kurung kurawal penutup@if. Kalau ada elemen lain di antaranya, compiler menolak:@else block can only be used after an @if or @else if block.@if (cariMenu(); as m)menyimpan hasil syaratnya ke namam, supaya isinya bisa dipakai di dalam blok tanpa dihitung ulang.
Latihan pertama memakai bentuk yang sama untuk tombol login:
@if (loggedIn) {
<p>Selamat datang!</p>
} @else {
<p>Silakan login</p>
}
<button (click)="loggedIn = !loggedIn">{{ loggedIn ? 'Logout' : 'Login' }}</button>
Mula-mula loggedIn bernilai false, jadi yang tampil Silakan login. Klik pertama membuatnya true dan paragrafnya diganti Selamat datang!; klik kedua mengembalikannya.
@for dan @empty
<ul>
@for (m of menu; track m.id) {
<li>{{ $index + 1 }}. {{ m.nama }}</li>
} @empty {
<li>Menu habis hari ini</li>
}
</ul>
m of menu: ambilmenudari class dan sebut tiap isinyam.track m.idwajib. Tanpatrack, template gagal dikompilasi:@for loop must have a "track" expression.@emptydirender kalau array-nya kosong, misalnyamenu = [].- Di dalam blok ada variabel bawaan. Untuk tiga menu tadi, Angular 18 mencetak:
| Baris | $index |
$first |
$last |
$even |
$count |
|---|---|---|---|---|---|
| Martabak Manis Cokelat Keju | 0 | true | false | true | 3 |
| Martabak Telur Spesial | 1 | false | false | false | 3 |
| Terang Bulan Pandan | 2 | false | true | true | 3 |
track: cara Angular mengenali baris
Saat array berubah, Angular gak membuang semua <li> lalu membuat ulang. Dia mencocokkan baris lama dengan isi baru lewat nilai track, lalu cuma memindah, menambah, atau membuang yang perlu. Jadi track gunanya melacak identitas item.
Misalnya tiap <li> punya <input placeholder="Catatan" />, kamu mengetik "tanpa daun bawang" di baris Martabak Manis Cokelat Keju, lalu balik() menjalankan this.menu = [...this.menu].reverse():
track |
Urutan sesudah dibalik | Catatan "tanpa daun bawang" ada di |
|---|---|---|
m.id |
Terang Bulan Pandan, Martabak Telur Spesial, Martabak Manis Cokelat Keju | baris ketiga, tetap di Martabak Manis Cokelat Keju |
$index |
sama | baris pertama, sekarang Terang Bulan Pandan |
Dengan track m.id, elemen <li> milik Martabak Manis Cokelat Keju ikut pindah ke bawah bersama kotak catatannya. Dengan track $index, Angular menganggap "baris ke-0 tetap baris ke-0": elemennya diam di tempat, cuma teksnya yang diganti, jadi catatanmu sekarang menempel di Terang Bulan Pandan. Itu jawaban tebakannya.
- Pakai id yang unik (
track m.id) untuk daftar yang bisa berubah urutan, ditambah, atau dihapus. track $indexaman untuk daftar diam yang gak pernah berubah, seperti daftar buah di latihan.- Kalau dua item punya nilai track yang sama, console menulis
NG0955: The provided track expression resulted in duplicated keys for a given collection.
@switch untuk status pesanan
@switch (status) {
@case ('diproses') { <p>Martabak sedang dibuat</p> }
@case ('dikirim') { <p>Kurir sedang di jalan</p> }
@case ('sampai') { <p>Pesanan sudah sampai</p> }
@default { <p>Status tidak dikenal</p> }
}
- Nilai
statusdibandingkan dengan tiap@casememakai===. Yang cocok dirender, yang lain gak ada di DOM. @defaultdirender kalau gak ada yang cocok, misalnyastatus = 'batal'.- Karena
===,status = 1gak cocok dengan@case ('1'): angka 1 dan teks '1' beda tipe, jadi yang tampil@default.
⚠️ Jebakan yang sering ketemu
@fortanpatrack. Seluruh template gagal dikompilasi. Tulis@for (item of buah; track $index)atautrack item.- Kedua paragraf ditulis di luar blok. Latihan pertama mengecek cuma ada satu
<p>di tiap keadaan. TaruhSelamat datang!di dalam@ifdanSilakan logindi dalam@else. - Lupa
@emptydi latihan kedua. Datanya gak pernah kosong, tapi kodenya dicek memuat@empty. - Tanda
@di teks biasa. Di Angular 17 sampai 18,@selalu membuka blok, jadi<p>Pesan lewat [email protected]</p>gagal:Incomplete block "gmail". If you meant to write the @ character, you should use the "@" HTML entity instead.Angular 22 (editor latihan) menampilkannya apa adanya. Di proyek yang masih Angular 18, tulisbangjali@gmail.com.
TL;DR: @if (syarat) { ... } @else if (...) { ... } @else { ... } merender cabang pertama yang benar dan membuang sisanya dari DOM; as menyimpan hasil syaratnya. @for (m of menu; track m.id) { ... } @empty { ... } mengulang satu bagian untuk tiap isi array, dengan $index, $first, $last, $even, dan $count; track wajib dan gunanya melacak identitas item, jadi saat daftar dibalik, track m.id memindah barisnya sedangkan track $index cuma mengganti teksnya. @switch (status) merender @case yang nilainya === status, atau @default. Semuanya bawaan template sejak Angular 17, tanpa import.