Dalam artikel kali ini akan coba dibawakan bagaimana mengimplementasikan CRUD (Create Read Update Delete) dalam Phoenix Liveview. Untuk kemudahan dan bisa memulai dengan cepat, bisa langsung melakukan git clone atau fork dari github repo berikut https://github.com/rizki96/liveview_todo.git.
Perlu diketahui, database yang digunakan kali ini adalah CubDB. Sedikit tentang CubDB, database ini adalah embedded key value database, dimana mekanisme penyimpanan datanya berlaku Copy On Write (COW) atau append only database untuk menjaga konsistensi data. Mekanisme ini berbeda dengan sqlite yang menggunakan mekanisme file locking. Dari mekanisme ini memungkinkan CubDB untuk disimpan dalam remote file system, seperti AWS S3 fuse mount atau google cloud storage fuse mount, atau file system seperti NFS maupun SMB. Karena dengan solusi remote file system biasanya fitur file locking tidak dijamin, sehingga tidak dimungkinkan sqlite berjalan dengan benar.
Untuk memulai mari kita bangun dulu interface untuk pengaksesan database CubDB. Interface ini akan disimpan dalam sebuah module elixir dalam file 'lib/liveview_todo/kv_store.ex'. Berikut isi dari file kv_store.ex
Module elixir ini pada hakikatnya adalah sebuah supervisor actor yang akan menjalankan worker engine dari CubDB. Worker engine tentunya akan dijalankan pada saat aplikasi dimulai, oleh sebab itu tambahkan module LiveviewTodo.KvStore ke dalam children supervisor, sebagai contoh nya adalah penggalan berikut pada file 'lib/liveview_todo/application.ex'
Kemudian terdapat 2 bagian besar dari module LiveviewTodo.KvStore, yaitu bagian dari MetaRecord dan bagian dari record data aplikasi. MetaRecord berisi informasi id yang terakhir di tulis dalam sebuah record data. Informasi mengenai record data ini disimpan dalam bentuk key, yang berisi nama tabel dan id. Dan record yang berisi value adalah informasi lengkap dari record data tersebut. Contoh adalah table todos, dengan record id 1, maka key-nya akan berisi {:todos, 1}.
Data file dari CubDB sendiri akan disimpan dalam config.exs, dimana path dari file ini akan dibaca oleh module file 'kv_store.ex' tersebut. Berikut sebagian isi dari 'config.exs' tempat penyimpanan data file dari CubDB
Phoenix framework sendiri mengenal konsep Context, dimana 'kv_store.ex' sebagai interface database tidak diperbolehkan untuk diakses langsung oleh aplikasi, tetapi harus melalui konsep Context ini. Untuk tiap aplikasi berbeda akan memiliki Context yang berbeda sesuai dengan domain aplikasi yang bersangkutan. Context aplikasi ini disimpan dalam module file 'lib/liveview_todo/tasks.ex' dimana dalam module ini terdapat query dan command yang akan diakses oleh aplikasi. Berikut isi dari module Context Tasks
Dalam Context Tasks ini terdapat CRUD module yang akan digunakan oleh aplikasi LiveView. Bagaimana penggunaan CRUD ini dalam LiveView ? Berikut module liveview yang telah dibuat pada artikel sebelumnya yaitu 'todo_live.ex', dengan ditambahkan fungsi list_todos untuk menampilkan semua data Todo.
Jika diperhatikan ada beberapa operasi pattern matching dalam kode ini. Seperti misalnya {:ok, todos} = Tasks.list_todos(), Dalam Elixir operator '=' bukan hanya berlaku sebagai assignment tapi juga sebagai match operator. Dimana match operator akan melakukan pencocokan antara sisi kiri dan kanan dari operasi '='. Kemudian dalam Phoenix (tidak hanya LiveView) dikenal perintah assign, contohnya adalah socket = assign(socket, todos: todos), perintah ini berfungsi untuk merubah state socket yang berisi variable yang dapat diakses dalam halaman HTML yang di render oleh LiveView. Dalam halaman HTML tersebut variable yang di assign dalam socket, seperti todos akan dikenal sebagai '@todos'. Dalam kode ini juga digunakan temporary_assigns seperti pada {:ok, assign(socket, temporary_assigns: [todos: []])}. temporary_assigns akan memberlakukan variable todos sebagai nilai sementara agar pada event berikutnya tidak dikirim semua data lagi ke halaman HTML LiveView. Fitur temporary_assigns ini yang akan membuat pengiriman data antara backend dan frontend menjadi efisien, karena semua data hanya akan dikirim sekali ketika event mount. Event berikutnya hanya data yang berubah saja yang akan dikirimkan. Perlu diketahui juga, data todos yang dikirim ke halaman HTML, ini secara otomatis akan di serialisasi kan sebagai data JSON, karena dalam module Tasks sebelumnya, module struct Todo telah ditambahkan line berikut : @derive {Jason.Encoder, only: [:id, :text, :completed]} , baris ini yang akan membuat framework Phoenix menginterpretasikan struct Todo menjadi JSON jika dibutuhkan, dan hanya field-field yang terpilih saja akan disertakan sebagai JSON object.
Kemudian bagaimana untuk menampilkan query list_todos ini dalam HTML ? Untuk itu mari kita buat LiveView Component yang berisi HTML dengan item-item 'todos'. Seperti sebelumnya buat Component dalam direktori 'lib/liveview_todo_web/live/components/todos' dengan nama file 'todo_list.ex' dan 'todo_list_item.ex'. Berturut-turut file tersebut berfungsi sebagai renderer untuk list of todos dan item todo. Berikut berturut-turut isi dari 'todo_list.ex' dan 'todo_list_item.ex'
Untuk mengetahui Component tersebut berfungsi, diharuskan untuk menambahkan Component tersebut ke halaman utama dari LiveView todo_live.html.leex. Sehingga halaman todo_live.html.leex akan berisi seperti berikut
Tentu saja setelah ini harus ditambahkan juga fungsi untuk melakukan penambahan dan pengubahan data ke dalam database. Sehingga file 'todo_live.ex' akan ditambahkan event untuk melakukan add dan update. Berikut ini isi dari 'todo_live.ex'
Dalam event yang akan di trigger dari halaman HTML pun mengenal pattern matching. Contohnya adalah baris 'def handle_event("add_todo", %{"todo" => todo} = _params, socket) do' dan 'def handle_event("update_todo:" <> todo_id, params, socket) do'. Parameter pada baris sebelumnya yaitu '%{"todo" => todo} = _params', params yang dikirim ke dalam event kita pattern match sebagai tipe map dan dilakukan ekstraksi terhadap nilai dalam map tersebut. Sedangkan params secara keseluruhan akan diabaikan dengan menambahkan '_' di depan nama variablenya. Begitu juga pada baris event berikutnya, "update_todo:" <> todo_id merupakan sebuah pattern match. Yang dilakukan disini adalah ekstraksi string untuk mendapatkan bagian yang dinginkan. Misalnya secara keseluruhan string nya adalah "update_todo:2" maka variable todo_id akan bernilai string '2'. Oleh sebab itu pattern matching adalah salah satu kekuatan dari bahasa Elixir untuk membuat kode lebih jelas dan ringkas.
Setelah fungsi add dan update, jalankan 'mix phx.server' untuk menjalankan phoenix web server dan akses ke halaman 'http://localhost:4000/todo'. Coba untuk menambahkan todo, misalnya adalah 'testing 1'. Maka akan terlihat seperti berikut ini
Bagaimana cara untuk melihat data yang dipertukarkan antara frontend dan backend dalam LiveView ? Buka bagian developer inspect element pada browser, kemudian pada bagian console javascript jalankan perintah liveSocket.enableDebug(). Berikut ini contoh gambarnya
Setelah itu coba untuk melakukan update dan akan terlihat hanya data yang berubah saja akan dikirim ke backend server. Contoh adalah sebagai berikut
Kemudian jika ditambahkan data todo berikutnya akan terlihat data baru ditambahkan pada element terakhir dari list_todo dan semua item todo terurut dari item todo yang lama ke item todo yang baru. Hal ini dimungkinkan dengan fitur DOM patching dari phoenix LiveView, dimana pada element list ditambahkan attribute phx-update="append". Bagaimana bila dibutuhkan sebaliknya ? data yang ditambahkan selalu berada diatas dan akan berurutan terbalik dari item todo yang baru ke item todo yang lama ? Caranya cukup mudah, yaitu ubah query list_todos menjadi reverse=true, query ini terdapat pada Context Tasks dan ubah nilai phx-update pada Component 'list_item.ex' menjadi phx-update="prepend". Maka ketika data ditambahkan todo akan terlihat seperti gambar dibawah
Bagaimana jika kita ingin menampilkan lebih Custom dari pada hanya sekedar append dan prepend. Jawabannya adalah gunakan JS Interop Hooks dalam LiveView.
Demikian bagian ke 2 dari artikel membangun web fullstack dengan menggunakan Phoenix LiveView, untuk JS Interop Hooks silahkan dicoba sebagai sebuah latihan, dan bisa dicoba juga untuk menambahkan fitur hapus. Terima kasih telah membaca artikel ini dan kemudian mencoba Phoenix LiveView, semoga lancar dan jika ada kritik, saran atau pertanyaan dapat langsung kontak melalui linkedin atau twitter di @rizki.
Top comments (0)