Web FullStack menggunakan Phoenix LiveView - Membangun Operasi CRUD
Tags: elixir, phoenixframework, phoenixliveview
Published: 2020-08-09 15:10:46

---
title: Web FullStack menggunakan Phoenix LiveView - Membangun Operasi CRUD
series: Web FullStack menggunakan Phoenix LiveView
---

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](https://github.com/rizki96/liveview_todo.git).

Perlu diketahui, database yang digunakan kali ini adalah [CubDB](https://github.com/lucaong/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

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=kv_store.ex-1 %}

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'

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=application.ex-1 %}

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

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=config.exs-1 %}

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

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=tasks.ex-1 %}

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.

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=todo_live.ex-1 %}

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'

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=todo_list.ex-1 %}

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=todo_list_item.ex-1  %}

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

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=todo_live.html.leex-1 %}

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'

{% gist https://gist.github.com/rizki96/7f8050d0cc58f196d8d27fdcb6255637 file=todo_live.ex-2 %}

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

![Tampilan todos app dengan LiveView](https://dev-to-uploads.s3.amazonaws.com/i/s1gbdxyej7iv1c373dxc.png)

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 

![Contoh liveSocket.enabledDebug()](https://dev-to-uploads.s3.amazonaws.com/i/7ryu17m23cowuq01bm9t.png)

Setelah itu coba untuk melakukan update dan akan terlihat hanya data yang berubah saja akan dikirim ke backend server. Contoh adalah sebagai berikut

<img src="https://dev-to-uploads.s3.amazonaws.com/i/dh0mwr4qtodv16v56ebe.png" width="500" alt="debug data yang dikirim ke backend server" />

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

<img src="https://dev-to-uploads.s3.amazonaws.com/i/edtrc6s6jgoz1q5iq27g.png" width="500" alt="item todo berurut dari terbaru ke yang lama" />

Bagaimana jika kita ingin menampilkan lebih *Custom* dari pada hanya sekedar *append dan prepend*. Jawabannya adalah gunakan [JS Interop Hooks](https://hexdocs.pm/phoenix_live_view/js-interop.html) 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](https://www.linkedin.com/in/iskandar-rizki-47063139/) atau twitter di [@rizki](https://twitter.com/rizki).