Reactive form adalah form yang aturannya dibangun di class: tiap kolom jadi objek FormControl, kolom-kolomnya dikumpulkan dalam FormGroup, dan template cuma menyambungkan tiap <input> ke kontrolnya. Bayangin formulir pesan-antar Martabak Bang Jali. Pembeli mengisi lembar kertasnya (template), tapi kasir memegang buku aturan sendiri: nama wajib, nomor HP diawali 08, jumlah minimal 1. Tiap kali pembeli menulis, kasir langsung menilai kolom itu dan tahu formulirnya sah atau belum.
🧪 Tebakan cepat: Form pesanan baru dibuka. Kolom HP masih kosong dan punya
Validators.required. Template-nya menulis@if (hp.errors) { <p>Nomor HP wajib diisi.</p> }. Pembeli belum menyentuh apa pun. Pesan itu sudah tampil? Jawabannya ada di bagian "Kapan pesan error ditampilkan".
FormGroup dan FormControl
import { Component } from '@angular/core'
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'
@Component({
selector: 'app-pesanan',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="pesanForm" (ngSubmit)="kirim()">
<input formControlName="nama" placeholder="Nama" />
@if (nama.touched && nama.errors?.['required']) {
<p class="error">Nama wajib diisi.</p>
}
<input formControlName="hp" placeholder="Nomor HP" />
@if (hp.touched && hp.errors?.['required']) {
<p class="error">Nomor HP wajib diisi.</p>
}
@if (hp.touched && hp.errors?.['pattern']) {
<p class="error">Nomor HP diawali 08, total 10 sampai 13 angka.</p>
}
<input formControlName="jumlah" type="number" />
@if (jumlah.touched && jumlah.errors) {
<p class="error">Jumlah minimal 1.</p>
}
<button type="submit" [disabled]="pesanForm.invalid">Kirim</button>
</form>
`,
})
export class Pesanan {
pesanForm = new FormGroup({
nama: new FormControl('', Validators.required),
hp: new FormControl('', [Validators.required, Validators.pattern('08[0-9]{8,11}')]),
jumlah: new FormControl(1, [Validators.required, Validators.min(1)]),
})
get nama() { return this.pesanForm.controls.nama }
get hp() { return this.pesanForm.controls.hp }
get jumlah() { return this.pesanForm.controls.jumlah }
constructor() {
this.pesanForm.valueChanges.subscribe((nilai) => console.log('valueChanges:', JSON.stringify(nilai)))
}
kirim() {
console.log('terkirim:', JSON.stringify(this.pesanForm.value))
}
}
ReactiveFormsModulediimportsmenyediakan[formGroup]danformControlName.new FormControl(nilaiAwal, aturan): satu kolom. Aturannya satu validator, atau array beberapa validator.new FormGroup({ ... })mengumpulkan kontrol-kontrol itu jadi satu form.pesanForm.valueberisi{ nama: '', hp: '', jumlah: 1 }, danpesanForm.validbarutruekalau semua kontrolnya lolos.[formGroup]="pesanForm"mengikat<form>ke grup itu, danformControlName="hp"menyambungkan satu<input>ke kontrol bernamahp. Grup yang cuma dibuat di class tanpa[formGroup]gak tersambung ke apa pun.(ngSubmit)="kirim()"jalan saat form dikirim: tombol submit diklik, atau Enter di salah satu kolom.- Getter
nama,hp, danjumlahcuma singkatan supaya template gak perlu menulispesanForm.controls.hpberulang kali.
Validators: aturan tiap kolom
| Validator | Gagal saat | Isi errors |
|---|---|---|
Validators.required |
kosong ('' atau null) |
{ required: true } |
Validators.min(1) |
angkanya di bawah 1 | { min: { min: 1, actual: 0 } } |
Validators.pattern('08[0-9]{8,11}') |
bukan 08 diikuti 8 sampai 11 angka | { pattern: { requiredPattern: '^08[0-9]{8,11}
|