Directive adalah instruksi yang ditempel ke elemen di template untuk mengubah cara elemen itu dirender atau tampil. Angular punya beberapa directive bawaan. Structural directive menambah atau membuang elemen: *ngFor mengulang, *ngIf menampilkan dengan syarat. Attribute directive mengubah tampilan elemen yang sudah ada: ngClass dan ngStyle. Bayangin papan menu Bang Jali lagi. Instruksi "tulis satu baris untuk tiap menu" itu *ngFor, "tulis Menu habis kalau gak ada menu" itu *ngIf, dan "coret yang stoknya nol" itu ngClass.
Sejak Angular 17, template punya cara bawaan yang lebih baru untuk mengulang dan memilih: blok @for dan @if. *ngFor dan *ngIf ditandai deprecated sejak Angular 20, tapi masih banyak di kode yang ada dan masih jalan di editor latihan (Angular 22). Pelajaran ini mengajarkan keduanya berdampingan.
🧪 Tebakan cepat: Kamu menulis
<li *ngFor="let m of menu">dengan tiga menu, tapi lupaimports: [NgFor]. Berapa<li>yang muncul: tiga, atau nol? Jawabannya ada di bagian "Kenapa daftarnya bisa kosong".
Mengulang: *ngFor dan @for
import { Component } from '@angular/core'
import { NgFor } from '@angular/common'
@Component({
selector: 'app-root',
standalone: true,
imports: [NgFor],
template: `
<ul>
<li *ngFor="let m of menu; let i = index">{{ i + 1 }}. {{ m }}</li>
</ul>
`,
})
export class App {
menu = ['Martabak Manis Cokelat Keju', 'Martabak Telur Spesial', 'Terang Bulan Pandan']
}
| Putaran | i |
m |
<li> yang dibuat |
|---|---|---|---|
| 1 | 0 | Martabak Manis Cokelat Keju | 1. Martabak Manis Cokelat Keju |
| 2 | 1 | Martabak Telur Spesial | 2. Martabak Telur Spesial |
| 3 | 2 | Terang Bulan Pandan | 3. Terang Bulan Pandan |
let m of menu: ambilmenudari class, dan sebut tiap isinyam. Pakaiof, bukanin.let i = index: posisi isinya, mulai dari 0.- Tanda bintang
*itu singkatan: Angular menjadikan<li>sebuah cetakan (<ng-template>), lalu mencetak satu salinan untuk tiap isi array. Elemen yang ditempeli*ngForitulah yang diulang. NgFordatang dari@angular/common, dan harus masukimportskomponen standalone.
Bentuk yang sekarang dipakai:
<ul>
@for (m of menu; track m) {
<li>{{ $index + 1 }}. {{ m }}</li>
} @empty {
<li>Menu habis hari ini</li>
}
</ul>
@forbagian dari template sejak Angular 17, jadi gak perlu import apa pun.track mwajib: itu cara Angular mengenali tiap baris saat daftarnya berubah. Untuk daftar teks yang unik, isinya sendiri cukup; untuk objek biasanyatrack m.id. Tanpatrack, compiler menolak:@for loop must have a "track" expression.$indexposisinya, mulai dari 0.@emptytampil kalau array-nya kosong.- Latihan pelajaran ini menerima
*ngFormaupun@for.
Menampilkan dengan syarat: *ngIf dan @if
<p *ngIf="menu.length === 0">Menu habis hari ini</p>
@if (menu.length === 0) {
<p>Menu habis hari ini</p>
} @else {
<p>{{ menu.length }} menu siap dipesan</p>
}
*ngIfmemasang elemennya ke DOM kalau syaratnya benar, dan membuangnya (bukan cuma menyembunyikan) kalau salah. PerluNgIfdiimports.@ifbawaan template dan punya@elsesendiri.*ngIfbutuh<ng-template>untuk bagian else; detailnya di pelajaran Control Flow.
Kenapa daftarnya bisa kosong
Hapus NgFor dari imports, dan Angular gak mengenali *ngFor. <li> tetap jadi cetakan yang gak pernah dicetak, jadi <ul> berisi nol <li>. Itu jawaban tebakannya. DOM-nya cuma <ul><!--container--></ul>, dan console menulis:
NG0303: Can't bind to 'ngForOf' since it isn't a known property of 'li' (used in the 'App' component template).
ngForOf adalah input yang dibuat Angular dari let m of menu. *ngIf tanpa NgIf berakhir sama: Can't bind to 'ngIf' since it isn't a known property of 'p'. @for dan @if gak punya masalah ini, karena keduanya bukan directive yang perlu di-import.
Mengubah tampilan: ngClass dan ngStyle
menu = [
{ nama: 'Martabak Manis Cokelat Keju', stok: 4 },
{ nama: 'Martabak Telur Spesial', stok: 6 },
{ nama: 'Terang Bulan Pandan', stok: 0 },
]
warnaPromo = 'crimson'
@for (m of menu; track m.nama) {
<li [ngClass]="{ habis: m.stok === 0, laris: m.stok > 5 }">{{ m.nama }}</li>
}
<p [ngStyle]="{ color: warnaPromo }">Promo malam ini</p>
[ngClass]menerima objek: tiap kunci adalah nama class, dan class itu dipasang kalau nilainya benar. Terang Bulan Pandan dapat classhabis, Martabak Telur Spesial dapatlaris, Martabak Manis Cokelat Keju gak dapat apa-apa.[ngStyle]menerima objek style dengan cara yang sama.- Keduanya perlu
NgClassatauNgStylediimports. Untuk satu class atau satu style, binding biasa lebih ringkas dan gak perlu import:[class.habis]="m.stok === 0"dan[style.color]="warnaPromo". Panduan Angular sekarang menyarankan bentuk ini.
⚠️ Jebakan yang sering ketemu
- Lupa
imports: [NgFor]. Nol<li>dan NG0303. Tambahkan import-nya, atau pakai@for. @fortanpatrack. Template gagal dikompilasi. Tulis@for (item of buah; track item).- Mengetik tiga
<li>dengan tangan. Tampilannya sama, tapi latihannya mengecek kodenya memakaingForatau@for. - Nomor ikut di teks. Latihan mengecek
<li>pertama persisApeldan yang terakhir persisJeruk.{{ i + 1 }}. {{ item }}membuatnya jadi1. Apel; di latihan cukup{{ item }}. - Dua structural directive di satu elemen.
<li *ngIf="..." *ngFor="...">ditolak:Can't have multiple template bindings on one element. Use only one attribute prefixed with *. Pakai@ifdi dalam@for.
TL;DR: Structural directive menambah atau membuang elemen: *ngFor="let m of menu; let i = index" mengulang satu elemen untuk tiap isi array, dan *ngIf="syarat" memasangnya cuma kalau syaratnya benar. Keduanya butuh NgFor atau NgIf di imports; kalau lupa, daftarnya kosong dan console menulis NG0303. Sejak Angular 17, @for (m of menu; track m) { ... } @empty { ... } dan @if (...) { ... } @else { ... } melakukan hal yang sama tanpa import, dan *ngFor/*ngIf deprecated sejak Angular 20. Attribute directive mengubah tampilan: [ngClass]="{ habis: m.stok === 0 }" memasang class yang nilainya benar, [ngStyle] memasang style; untuk satu class atau style, [class.habis] dan [style.color] lebih ringkas.