v-model mengikat sebuah kolom form dengan data reaktif ke dua arah: mengetik mengubah datanya, dan mengubah datanya mengubah isi kolom. Ini disebut two-way binding. Bayangin papan tulis kecil di meja kasir Warung Bu Sri yang dipakai berdua. Pembeli menulis pesanannya di papan, Bu Sri membaca dari papan yang sama. Kalau Bu Sri menghapus tulisan "pedas" karena cabainya habis, pembeli langsung melihatnya terhapus. Satu papan, dua arah. v-model membuat kolom form dan ref jadi satu papan seperti itu.
🧪 Tebakan cepat: Ada
const nasi = ref(0)danconst teh = ref(0), dua kolom<input v-model="nasi" />dan<input v-model="teh" />, lalu<p>Total porsi: {{ nasi + teh }}</p>. Pembeli mengganti isi kolom pertama jadi 1 dan kolom kedua jadi 2. Total porsinya berapa? Tebak dulu, jawabannya ada di bagian ".number, .trim, .lazy".
v-model: kolom dan data jadi satu
const nama = ref("")
---template---
<input v-model="nama" placeholder="Nama pemesan" />
<p>Pesanan atas nama: {{ nama }}</p>
<button @click="nama = ''">Hapus</button>
| Kejadian | nama |
Isi kolom | Paragraf |
|---|---|---|---|
| Halaman tampil | "" |
kosong | Pesanan atas nama: |
| Ketik "Sri" | "Sri" |
Sri | Pesanan atas nama: Sri |
| Klik Hapus | "" |
kosong | Pesanan atas nama: |
- Arah pertama: setiap ketikan langsung ditulis ke
nama, tanpa tombol apa pun. - Arah kedua:
nama = ''di tombol Hapus mengosongkan datanya, dan kolomnya ikut kosong. - Untuk kolom teks,
v-model="nama"kira-kira sama dengan:value="nama"ditambah@input="nama = $event.target.value"dari pelajaran event. Checkbox dan radio memakaicheckeddan eventchange, select memakai eventchange.v-modelmengurus semuanya. - Latihan pertama:
<input id="nama" v-model="nama" />dan<p id="preview">{{ nama }}</p>. KetikSinta, paragrafnya langsung berbunyiSinta. - Nilai awal kolom datang dari ref-nya. Atribut
valuediabaikan:<input v-model="nama" value="Budi" />dengannamaberisi""tampil kosong. - Isi
v-modelharus sesuatu yang bisa ditulis: nama ref, atau properti sepertikeranjang.catatan.v-model="nama.toUpperCase()"gagal di-compile. Build development menulis[Vue warn]: Template compilation error: v-model value must be a valid JavaScript member expression., dan Playground cuma menampilkanhttps://vuejs.org/error-reference/#compiler-42.
Checkbox, radio, select, dan textarea
const bungkus = ref(false)
const tambahan = ref([])
const pedas = ref("Sedang")
const menu = ref("Mie Ayam")
const catatan = ref("")
---template---
<label><input type="checkbox" v-model="bungkus" /> Dibungkus</label>
<label><input type="checkbox" value="Telur" v-model="tambahan" /> Telur</label>
<label><input type="checkbox" value="Kerupuk" v-model="tambahan" /> Kerupuk</label>
<label><input type="radio" value="Tidak pedas" v-model="pedas" /> Tidak pedas</label>
<label><input type="radio" value="Sedang" v-model="pedas" /> Sedang</label>
<label><input type="radio" value="Pedas" v-model="pedas" /> Pedas</label>
<select v-model="menu">
<option>Nasi Goreng</option>
<option>Mie Ayam</option>
<option>Es Teh</option>
</select>
<textarea v-model="catatan"></textarea>
| Elemen | Isi data | Contoh |
|---|---|---|
| Satu checkbox | true atau false |
centang Dibungkus: bungkus jadi true |
| Beberapa checkbox, satu array | array berisi value yang dicentang |
centang Kerupuk lalu Telur: ["Kerupuk", "Telur"] |
| Radio | value yang dipilih |
pilih Pedas: "Pedas" |
| Select | value opsi yang dipilih, atau teksnya kalau gak ada value |
dari awal Mie Ayam terpilih |
| Textarea | teksnya | "tanpa sayur" |
- Nilai awal ref menentukan opsi yang terpilih. Latihan kedua:
const warna = ref("Merah"),<select id="warna" v-model="warna">dengan opsi Merah, Hijau, Biru, lalu<p id="pilihan">{{ warna }}</p>. Dari awal paragrafnya berbunyiMerah; pilih Hijau, jadiHijau; pilih Biru, jadiBiru. - Beberapa checkbox untuk satu data harus dimulai dari array,
ref([]). Urutan isinya mengikuti urutan dicentang. - Isi textarea lewat
v-model, bukan{{ }}di antara tag-nya.
.number, .trim, .lazy
const nasi = ref(0)
const teh = ref(0)
---template---
<input v-model="nasi" /> porsi Nasi Goreng
<input v-model="teh" /> gelas Es Teh
<p>Total porsi: {{ nasi + teh }}</p>
| Ditulis | nasi sesudah diisi 1 |
Total, sesudah diisi 1 dan 2 |
|---|---|---|
v-model="nasi" |
"1", teks |
12 |
v-model.number="nasi" |
1, angka |
3 |
Tanpa .number, totalnya 12. Itu jawaban tebakannya. Isi kolom input selalu teks, jadi "1" + "2" menyambung teks, bukan menjumlah angka. Perkalian kebetulan tetap benar ("1" * 15000 jadi 15000), dan karena itu bug ini sering lolos.
| Modifier | Yang dilakukan | Contoh |
|---|---|---|
.number |
mengubah isi kolom jadi angka | "2 porsi" jadi 2; "dua" tetap teks "dua" karena gak bisa jadi angka |
.trim |
membuang spasi di awal dan akhir | " Sri " jadi "Sri" |
.lazy |
baru menulis ke data saat event change, yaitu saat kolom ditinggalkan atau Enter ditekan |
mengetik "Sri" belum mengubah nama |
<input type="number" v-model="nasi" />sudah otomatis jadi angka di Vue 3. Hati-hati: kolom angka yang dikosongkan berisi teks"".- Modifier boleh dirangkai:
v-model.trim.lazy="nama".
⚠️ Jebakan yang sering ketemu
- Angka yang ternyata teks.
{{ nasi + teh }}menghasilkan12, bukan3. Pakaiv-model.numberatautype="number". .lazyuntuk pratinjau langsung. Dengan.lazy, paragraf baru berubah sesudah kolomnya ditinggalkan. Latihan pertama mengetikSintadan langsung membaca#preview, jadi pakaiv-modelbiasa.- Checkbox grup tanpa array. Kalau
tambahandimulai dariref(""), mencentang satu kotak membuattambahanjaditrue, dan semua kotak di grup itu ikut tercentang. valueatauselecteddi HTML.v-modelmengabaikannya. Nilai awal ditulis di ref:ref("Merah").
TL;DR: v-model="nama" mengikat kolom form dan ref ke dua arah: mengetik mengubah data, mengubah data mengubah kolom. Kolom teks dan textarea memberi teks, satu checkbox memberi true atau false, beberapa checkbox dengan ref([]) memberi array value yang dicentang, radio dan select memberi value yang dipilih, dan nilai awal ref menentukan apa yang terpilih. Isi kolom selalu teks, jadi .number mengubahnya jadi angka; .trim membuang spasi di ujung; .lazy menunggu event change. Atribut value diabaikan, dan isi v-model harus ref atau properti yang bisa ditulis.