Gabut Mode On: Bikin Aplikasi Inventaris Kosan (Bagian 4 - Create Item)
Tags: webdev, javascript, beginners, bahasa
Published: 2020-04-28 12:48:15

Halooo.

Hari ini saya akan membuat fitur untuk memenuhi user story pertama, yaitu mencatat barang-barang. Nama fiturnya "Create Item". 

Tapi sebelum itu,

## TL;DR
Yang doyan instan-instan, boleh langsung ke bagian paling bawah untuk melihat hasil akhir bagian ini. 

---

OK, Jadi, bentuk paling sederhana dari fitur ini akan memungkinkan user untuk memasukkan nama barang dan deskripsinya. Gampang to. Tapi sebelum mulai membuat fitur, bersihkan dulu hasil persiapan sebelumnya.  

```html
<!-- index.html -->
<body>
  <div id="app">
    
  </div>

  <script src="vue.js"></script>
  <script src="index.js"></script>
</body>
```

```javascript
// index.js
new Vue({
  el: '#app',
  data(){
    return {

    }
  }
})
```

---

Nah, perlu diketahui kalau file html pada halaman website itu seharusnya bukan dibuka dengan cara dobel klik. Harusnya mereka dibuka pakai web server. Dikarenakan pembahasan web server itu ribet, saya pakai web server dari extension VS Code, namanya Live Server. Googling aja ya. Kalau pembaca mau pakai web server lain ya jelas boleh dong.

---

Mari kita mulai membuat fitur "Create Item". 

Yang kita butuhkan adalah 2 buah input dari user, dan sebuah tombol. Satu input berupa teks untuk nama barangnya apa, yang satu lagi teks agak banyak untuk deskripsi barangnya, tombolnya untuk mengirim hasil inputan user. Input ya `<input>`, agak banyak dikit ya `<textarea>`, kalau tombol ya `<button>`. 

Langsung pasang aja di dalam aplikasi Vue-nya.

```html
...
  <div id="app">
    <input>
    <textarea></textarea>
    <button>add</button>
  </div>
...
```

Kalau dilihat, hasilnya jelek. Putih semua, cuma ada tulisan "add" kecil. Ga jelas. Ini karena Tailwind punya jurus me-normal-kan elemen-elemen HTML jadi konsisten di semua modern browser. Kurang tahu detailnya gimana, tapi ada semacam [Reset](https://meyerweb.com/eric/tools/css/reset/) atau [Normalize](https://necolas.github.io/normalize.css/) di tubuh Tailwind. Makanya jadi polos gitu elemen-elemennya.

Ayo kita kasih style dikit supaya bisa terlihat manusia.

```html
  <div id="app">
    <input class="border" placeholder="name">
    <textarea class="border" placeholder="description"></textarea>
    <button class="border">add</button>
  </div>
```

Kalau dilihat, masih jelek sih. Tapi lebih manusiawi.

Sekarang kita pasang penyadap di elemen-elemen berjenis input. Supaya kita bisa tahu si user masukin apa aja.

```html
...
    <input class="border" placeholder="name" @change="handleChange">
    <textarea class="border" placeholder="description" @change="handleChange"></textarea>
...
```

```javascript
new Vue({
  el: '#app',
  data(){
    return {

    }
  },
  
  // tambah ini nih
  methods: {
    handleChange(e){
      console.log(e)
    }
  }
})
```

Kalau kalian belum paham cara pakai `console.log`, sudah pasti kalian tidak bisa meneruskan perjalanan ini. Kalian harus kembali ke padepokan [w3schools](https://www.w3schools.com/jsref/met_console_log.asp).

Bagi yang sudah ahli ber`console.log` ria, coba dicek apakah fungsinya sudah bekerja dengan baik ketika user memasukkan sesuatu.

Oke sip, muncul Event Object yang di dalamnya ada sesuatu dari si user. Kita simpan sesuatunya ke suatu tempat.

```javascript
new Vue({
  el: '#app',
  data(){
    return {
      
      // ini wadahnya
      item: {}
    }
  },
  methods: {
    handleChange(e){

      // ketika user masukin sesuatu, edit this.item nya
      this.item = {
        
        // ambil isi yang lama
        ...this.item,
        
        // tambahin apa yang user masukin
        [e.target.name]: e.target.value
      }

      console.log(this.item)
    }
  }
})
```

```html
    <input class="border" placeholder="name" @change="handleChange" name="name">
    <textarea class="border" placeholder="description" @change="handleChange" name="description"></textarea>
```

Kita kasih nama dulu elemen-elemennya, terus masukin isi dari elemen itu ke datanya Vue yang `this.item` setiap kali user nge`change` alias nge-ganti isi elemen input.

---

Sekarang kita pasang pendengar juga ke tombolnya, untuk nantinya memproses `this.item` yang sudah kita simpan. Pasang aja dulu ya kan.

```html
...
    <button class="border" @click="add">add</button>
...
```

```javascript
// index.js
...
  methods: {
    handleChange(e){
      this.item = {
        ...this.item,
        [e.target.name]: e.target.value
      }

      console.log(this.item)
    },
    add(){
      console.log('ini yang mau diproses:', this.item)
    }
  }
...
```

Sip, mantap.

`this.item` itu wadah untuk barang yang diinput user. Bagaimana kalau user mau nginput barang selanjutnya? Padahal cuma ada satu wadah yaitu `this.item`?

`this.item`nya kita simpan dulu ke wadah yang lebih besar. Yuk.

```javascript
...
  data(){
    return {
      item: {},
      
      // ini dia wadah yang lebih besar!
      items: []
    }
  },
...
```

```javascript
    add(){
      console.log('ini yang mau diproses:', this.item)

      // masukin yang mau diproses ke wadahnya
      this.items.push(this.item)
      
      console.log(this.items)
    }
```

Cakep. Coba dites dulu.

Ada yang aneh, ya. Setelah user masuk barang pertama, itu para input masih ada aja isinya. Lebih enak kalau langsung dikosongin kali ya.

```javascript
    add(){
      console.log('ini yang mau diproses:', this.item)

      // masukin yang mau diproses ke wadahnya
      this.items.push(this.item)
      
      console.log(this.items)
      
      // kembalikan ke asalnya
      this.item = {}
    }
```

Hmm. Tetep ada isinya. Harus kita kasih tali buat kontrol tingkah lakunya. Kayak kuda gitu. Kalau ga salah istilahnya: _[binding](https://vuejs.org/v2/guide/forms.html)_.

Dengan rencana mem-binding input ini, nanti kita bisa menghapus `handleChange`, karena sudah di-handle sama Vue. Kita juga akan merubah cara kita menangkap inputan dari user.

Jadinya gini nih:

```html
...
    <!-- 
       Perhatikan, "@change" sudah tidak ada. 
       Sedangkan atribut "name" diganti jadi "v-model"
    -->
    <input class="border" placeholder="name" v-model="name">
    <textarea class="border" placeholder="description" v-model="description"></textarea>
...
```

```javascript
new Vue({
  el: '#app',
  data(){
    return {
      items: [],

      // "item" kita hapus, terus modelnya kita pajang.
      name: '',
      description: ''
    }
  },
  methods: {
    // tadinya disini ada method "handleChange" kan?
    // kita buang, karena sudah di-handle Vue.

    add(){

      // nah, si "this.item" berubah, jadi variable biasa.
      // isinya model "name" sama "description"
      let item = {
        name: this.name,
        description: this.description
      }
      
      // perhatikan, tidak ada lagi "this.item".
      console.log('ini yang mau diproses:', item)

      this.items.push(item)

      console.log(this.items)
      
      // Kita polosin lagi modelnya. Biar bisa ganti-ganti. hehe
      this.name = ''
      this.description = ''
    }
  }
})
```

### Josss!

Selesai sudah fitur mencatatnya. Masih jelek sih, tapi yang namanya progres itu dari kosong jadi satu, dari satu jadi dua. Dari ga ada ke jelek, dari jelek ke bagus. Pelan-pelan aja yang penting maju terus.

## Bungkus!

```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="tailwind.css">
</head>
<body>
  <div id="app">
    <input class="border" placeholder="name" v-model="name" value>
    <textarea class="border" placeholder="description" v-model="description"></textarea>
    <button class="border" @click="add">add</button>
  </div>

  <script src="vue.js"></script>
  <script src="index.js"></script>
</body>
</html>
```

```javascript
// index.js
new Vue({
  el: '#app',
  data(){
    return {
      items: [],
      name: '',
      description: ''
    }
  },
  methods: {
    add(){
      let item = {
        name: this.name,
        description: this.description
      }

      this.items.push(item)

      this.name = ''
      this.description = ''

      console.log(this.items)
    }
  }
})
```

---

Jangan terburu-buru, sediakan waktu untuk memandangi kodenya. Segera kita akan melaju ke lap berikutnya. Dadah.