Input dan output adalah cara dua komponen bicara. Input membawa data dari komponen induk (parent) ke komponen anak (child): App memberi tahu kartu menu nama dan harganya. Output membawa kejadian dari anak ke induk: kartu memberi tahu App "ada yang memesan aku". Bayangin kartu menu kosong di Martabak Bang Jali. Bang Jali (App) menulis nama dan harga di tiap kartu, itu input. Tiap kartu punya bel kecil bertuliskan Pesan; saat dibunyikan, Bang Jali mendengar dan menaruh martabaknya ke keranjang, itu output.
🧪 Tebakan cepat: App menulis
<app-menu-item [nama]="Martabak Telur Spesial" />, tanpa tanda kutip tunggal di dalamnya. Apa yang tampil di kartu? Jawabannya ada di bagian "Kurung siku membaca kode, bukan teks".
@Input(): App mengisi kartu
// src/app/menu-item/menu-item.ts
import { Component, Input } from '@angular/core'
@Component({
selector: 'app-menu-item',
standalone: true,
template: `
<div class="kartu">
<h3>{{ nama }}</h3>
<p>Rp{{ harga }}</p>
</div>
`,
})
export class MenuItem {
@Input() nama = ''
@Input() harga = 0
}
<!-- template App, dengan imports: [MenuItem] -->
@for (m of menu; track m.id) {
<app-menu-item [nama]="m.nama" [harga]="m.harga" />
}
menu = [
{ id: 1, nama: 'Martabak Manis Cokelat Keju', harga: 40000 },
{ id: 2, nama: 'Martabak Telur Spesial', harga: 50000 },
{ id: 3, nama: 'Terang Bulan Pandan', harga: 35000 },
]
@Input()menandai properti yang boleh diisi dari luar. Tanpa tanda itu, properti cuma hidup di dalam komponennya sendiri.[nama]="m.nama"di template App mengirim nilaim.namake propertinamamilik kartu itu. Hasilnya tiga kartu dari satu class: Martabak Manis Cokelat Keju Rp40000, Martabak Telur Spesial Rp50000, Terang Bulan Pandan Rp35000.nama = ''adalah nilai awal, dipakai selama induknya gak mengirim apa pun.- Lupa
@Input(), dan Angular menolak binding-nya. Kartunya kosong, dan console menulisNG0303: Can't bind to 'nama' since it isn't a known property of 'app-menu-item'.
Latihan memakai bentuk yang sama:
@Component({
selector: 'app-greeting',
standalone: true,
template: `<h2>Halo, {{ nama }}!</h2>`,
})
export class GreetingComponent {
@Input() nama = ''
}
Di editor latihan, komponen ini dijalankan sendirian tanpa induk, jadi yang tampil Halo, !: gak ada yang mengirim nama, dan nilai awalnya teks kosong. Itu wajar.
Kurung siku membaca kode, bukan teks
Isi [nama]="..." dibaca sebagai kode TypeScript, sama seperti {{ }}. Jadi:
| Ditulis di App | Yang diterima kartu |
|---|---|
[nama]="m.nama" |
isi properti m.nama |
[nama]="'Martabak Telur Spesial'" |
teks Martabak Telur Spesial |
nama="Martabak Telur Spesial" |
teks yang sama, tanpa kurung siku |
[pesan]="Halo" |
properti App bernama Halo, yang gak ada, jadi kosong |
[nama]="Martabak Telur Spesial" |
gak ada: template gagal dikompilasi |
Tiga kata tanpa tanda kutip bukan kode yang sah, jadi Angular 18 menolak seluruh template App: Parser Error: Unexpected token 'Telur' at column 10 in [Martabak Telur Spesial]. Kartunya gak tampil, bahkan judul App pun gak. Itu jawaban tebakannya. Untuk teks, pakai tanda kutip tunggal di dalam tanda kutip ganda, atau buang kurung sikunya.
@Output(): kartu memberi tahu App
// di MenuItem: tambahkan Output dan EventEmitter ke import
@Output() pesan = new EventEmitter<string>()
pesanIni() {
this.pesan.emit(this.nama)
}
// template kartu: <button (click)="pesanIni()">Pesan</button>
<!-- template App -->
<app-menu-item [nama]="m.nama" [harga]="m.harga" (pesan)="tambahKeKeranjang($event)" />
<p>Keranjang: {{ keranjang.join(', ') }}</p>
keranjang: string[] = []
tambahKeKeranjang(nama: string) {
this.keranjang = [...this.keranjang, nama]
}
| Kejadian | $event |
Tampil |
|---|---|---|
| Render pertama | Keranjang: | |
| Pesan di kartu Terang Bulan Pandan | 'Terang Bulan Pandan' |
Keranjang: Terang Bulan Pandan |
| Pesan di kartu Martabak Telur Spesial | 'Martabak Telur Spesial' |
Keranjang: Terang Bulan Pandan, Martabak Telur Spesial |
@Output()menandai event yang bisa didengar induknya.EventEmitter<string>berarti event ini membawa satu teks.this.pesan.emit(this.nama)membunyikan bel-nya dan menitipkan nama martabaknya.- Di App,
(pesan)didengar seperti(click), dan$eventberisi nilai yang di-emit, bukan objek event DOM. - Nama event di App harus sama persis dengan nama properti output-nya.
(dipesan)gak menangkap apa pun, dan gak ada error yang muncul.
Data mengalir satu arah
Input cuma mengalir turun. Kalau kartu mengubah this.nama miliknya sendiri, cuma kartu itu yang berubah: menu di App tetap sama. Begitu App mengganti nilainya, Angular menimpa salinan di kartu dengan nilai baru dari App. Jadi anak yang ingin mengubah data milik induk gak mengubahnya sendiri, tapi meng-emit output dan membiarkan induknya yang mengubah, seperti tambahKeKeranjang tadi.
💡 Opsi @Input: required dan transform
@Input({ required: true }) nama!: string
@Input({ transform: booleanAttribute }) favorit = false
required: truemembuat build proyek Angular CLI gagal kalau induknya lupa mengirim[nama]. Editor latihan gak memeriksa ini: kartunya tetap tampil dengan nama kosong.transform: booleanAttribute(diimpor dari@angular/core) mengubah atribut polos jadi boolean:<app-menu-item favorit />memberifavoritbernilaitrue. Tanpa transform, nilainya teks kosong''.- Atribut tanpa kurung siku selalu mengirim teks:
harga="50000"memberi teks'50000', bukan angka. Pakai[harga]="50000", atautransform: numberAttribute.
💡 Bentuk signal: input() dan output()
nama = input('')
harga = input.required<number>()
pesan = output<string>()
- Ini bentuk yang sekarang disarankan dokumentasi Angular untuk kode baru. Nilainya dibaca sebagai fungsi:
{{ nama() }}. Lupa kurungnya, dan{{ nama }}mencetak fungsi signal-nya sebagai teks seperti[Input Signal: ...]. input()gak bisa diubah dari dalam kartu:this.nama.set(...)gak ada.- Editor latihan dan Playground menjalankan Angular 22 tanpa Angular CLI, dan di sana
input(),output(), danmodel()gak dikenali sebagai input atau output: console menulisNG0303: Can't bind to 'nama' since it isn't a known property of 'app-menu-item'. Karena itu latihan dan Playground memakai@Input()dan@Output().
⚠️ Jebakan yang sering ketemu
- Teks tanpa tanda kutip di kurung siku.
[nama]="Martabak Telur Spesial"menggagalkan seluruh template. Tulis[nama]="'Martabak Telur Spesial'"ataunama="Martabak Telur Spesial". - Lupa
@Input(). Binding-nya ditolak dengan NG0303 dan kartunya kosong. - Nama event beda dengan nama output.
(dipesan)untuk outputpesandiam saja, tanpa error. - Bentuk lain di latihan. Latihan mengecek kodenya memuat
@Input()yang langsung diikutinama, dan{{ nama }}di dalam<h2>.@Input({ required: true }) namaataunama = input('')gak lolos pengecekan itu.
TL;DR: @Input() nama = '' membuat properti yang diisi induk lewat [nama]="m.nama"; isi kurung siku dibaca sebagai kode, jadi teks butuh tanda kutip tunggal ([pesan]="'Halo'" mengirim Halo) atau tanpa kurung siku sama sekali. @Output() pesan = new EventEmitter<string>() plus this.pesan.emit(this.nama) mengirim kejadian ke atas, dan induknya mendengarkan dengan (pesan)="tambahKeKeranjang($event)", di mana $event adalah nilai yang di-emit. Data mengalir turun lewat input, kejadian naik lewat output. input() dan output() adalah bentuk signal-nya untuk proyek Angular CLI.