Konsep powerful Vue v-model: Membuat custom dan reusable modal
Use case kali ini sering kita temui tapi banyak yang masih bingung gimana implementasinya.
Sesuai janji di artikel atas, saya akan coba bikin satu artikel lagi masih dengan topik yang sama seputar v-model di Vue. Kita akan coba bahas 1 konsep Vue, menggunakan 1 use case spesifik. Harapannya, konsep ini bisa kamu implementasikan di use case lainnya. Cukup pahami konsep saja.
Background
Jadi, baru-baru ini saya diminta bikin 1 halaman web yang isinya list file dokumen yang di-upload sama user. Nantinya, di halaman ini bakal ada 1 tombol utama yang memungkinan user untuk upload satu atau beberapa dokument sekaligus.
Kira-kira sketch nya akan seperti ini:
Persiapan
Kita mulai dari menginstall Vue 2. (Cara install Vue tidak akan saya jelaskan disini, silahkan pelajari secara mandiri). Disini kita akan coba pakai framework UI BootstrapVue (https://bootstrap-vue.org/docs).
Untuk menampilkan data ke dalam table, kita akan gunakan data dari `https://dummyjson.com/products`.
Action
Untuk memulai tahap coding, kita perlu memanggil API dari fileApp.vue
, yang nantinya data tersebut akan kita passing ke component ProductList.vue
(belum kita bikin).
Begini cara saya passing data dari API ke component ProductList.vue
:
Setelah itu, kita bikin 1 folder baru di dalam folder src, yaitu Component. Kemudian kita akan coba bikin file ProductList.vue
di dalam folder tsb, yang isinya adalah table dari product itu sendiri begini hasil akhirnya:
Lanjut, sekarang kita perlu bikin file modalnya di dalam folder components. Modal ini fungsinya cuma buat liat informasi lebih banyak dari product yang kita klik di table ProductList.vue
. Kita kasih nama ProductModal.vue
. Hasilnya begini:
Sampai disini, kita belum menambahkan component ProductModal.vue
ke dalam vue app kita. Kita harus import file ini supaya button nya bisa tampil.
Sekarang kita balik ke file ProductList.vue
, modifikasi file tersebut jadi seperti ini:
Dan harusnya sekarang sudah tampil seperti ini:
Bagian penting
Ok sekarang kita udah bisa menampilkan seluruh data dari API ke dalam table. Tapi data-nya masih belum diolah. Kalau di-scroll secara horizontal, ada 1 column yang title nya images dan thumbnail. Nanti nya kita bakal custom data table ini menjadi hanya menampikan 3–4 data saja, jadi user tidak perlu scroll horizontally untuk melihat keseluruhan data. Cukup klik product title nya, maka akan menampilkan seluruh detail data.
Mari kita bikin modal nya muncul dulu.
Di component ProductModal.vue
, kita akan “menangkap” variabel bertipe boolean dari ProductList.vue
yaitu berupa flag yang bernilai false untuk menutup modal, dan bernilai true untuk menangkap modal.
Modifikasi script di ProductModal.vue
menjadi seperti ini:
Disini kita akan menangkap property “value” dari ProductList.vue
dan akan kita pakai value tersebut untuk menampilkan/menutup modal. Lebih lanjut, kita bakal modifikasi file ini dengan urutan berikut:
- Hapus data options.
- Ganti click listener di button “Open modal” menjadi “value != value”
- Ganti value v-model dari component <b-modal /> dari “modalShow” menjadi “value”.
Lalu di file ProductList.vue
, kita perlu modifikasi file nya:
- Tambahkan v-model di component <product-modal />
- Tambahkan data options
isModalShow: false
.
Hasilnya akan jadi seperti ini:
Pertanyaannya: kenapa props nya “value” tapi yang kita lempar itu adalah “v-model”?
Nah, penjelasan konsepnya sudah saya jelaskan di artikel saya sebelumnya:
Jadi, intinya adalah, “value” di props component ProductModal.vue
, yang ini:
Menangkap isi dari modifier v-model
yang kita lempar di component ProductList.vue
. Karena sejatinya v-model itu adalah shorthand dari
value="value" @input=" x => value = x.target.value"
Yang mana dia sebenarnya melempar isi dari variable “value”. Dan isi “value” itu ditangkap di child component ProductModal.vue
sebagai prop “value”.
Saya agak kesulitan menjelaskan prinsip itu, tapi semoga penjelasan saya mudah dipahami.
Bug
Dari kode di atas, kita menemukan 1 bug yaitu di mana props value itu sebenarnya tidak boleh mutasi/dimodifikasi secara langsung, karena mutating prop itu sudah termasuk anti-pattern.
Penjelasannya sudah banyak ada di Google. Salah satunya bisa dibaca di sini:
Jadi, gimana cara kita solve bug ini?
Caranya, modifikasi component ProductModal.vue
jadi begini:
- Bikin computed property untuk toggle isi variable dari prop “value”, misalnya “isModalOpen”.
- Binding value dari “isModalOpen” ke v-model component <b-modal />
Hasilnya begini:
Ketika dijalankan, maka hasilnya akan jadi seperti ini:
Kita bakal membuat modal ini menjadi “lebih bermakna” dengan passing data product sesuai yang diklik di table.
Dengan sedikit modifikasi menambahkan data API di component ProductModal.vue
, ketika kita meng-klik salah satu item di table maka kita akan mendapatkan hasil seperti ini:
Code lengkap nya bisa dilihat di sini:
Sekian dan terima kasih!