มาทำ Data two-way binding ใน vue.js 2 กัน ตอน 2

มาทำ Data two-way binding ใน vue.js 2 กัน ตอน 2
Itthipat.me

ใครที่ยังไม่ได้อ่านตอน 1 แนะนำให้กลับไปอ่านก่อนครับจะได้เข้าใจการ emit event กลับมาด้วย ส่วนใครที่อ่านแล้วมาลุยกันต่อเลยครับ

ตอนที่ 1 คลิก


ในการกด click แล้วให้เพิ่ม component เข้าไปคงหนีไม่พ้นการใช้ array และ v-for เข้าช่วยเมื่อ click ก็ทำการ push array เข้าไป v-for ก็จะทำการเพิ่ม component เอง

เรามาแก้ไขไฟล์ TodoList.vue กัน

<template>
  <div class="container">
    <div class="field-warp">
      <field-list v-for="(list, index) in lists" 
      :key="list.key" 
      @update:title="value => list.title = value"
      @update:description="value => list.description = value"
      :title="list.title"
      :description="list.description"></field-list>
    </div>
    <pre>{{ lists }}</pre>
    <button type="button" class="btn-add" @click="addField">Add Field</button>
  </div>
</template>
<script>
import FieldList from './FieldList'
export default {
components: {
    FieldList
  },
data() {
    return {
      lists: [
        { key: 0, title: '', description: '' }
      ],
      indexKey: 0
    }
  },
methods: {
    addField() {
      const index = this.indexKey += 1
      this.lists.push({ key: index, title: '', description: '' })
    }
  }
}
</script>
<style>
.container {
  width: 960px;
  margin: 0 auto;
  text-align: center;
}
.field-warp {
  display: block;
}
.btn-add {
  margin-top: 30px;
}
</style>

เรามาแยกการทำงานทีละส่วนของไฟล์ TodoList.vue กันเริ่มจาก

<field-list v-for="(list, index) in lists" 
      :key="index" 
      @update:title="value => list.title = value"
      @update:description="value => list.description = value"
      :title="list.title"
      :description="list.description"></field-list>

v-for ทำการ loop ตัวแปล lists แต่ละตัวแยกออกมาโดยในแต่ละรอบจะมี list และ index แยกจากกัน

:key ทำการส่ง index เข้าไปเพื่อนกำหนด key ให้กับตัว component

**** อัพเดท ***
คำเตือนในส่วนของ :key ที่ใช้ค่า index ส่งไปควรสร้าง indexKey แล้วให้รัน index ด้วยตัวเองเพราะเมื่อมีการสั่งลบ array lists ตัว key จะ render ใหม่และจะทับกับของเดิมเช่นตัวเก่ามี 1,2,3 เราจะทำการลบ 2 ออกจะเหลือ 1,3 ตัว lists จะ render ใหม่แต่เลข index ตัวที่ 3 ขยับมาเป็น 2 ทำให้ vuejs คิดว่าเราต้องการลบตัวที่ 3 แทนครับเพราะรู้สึกว่า dataจะอัพเดทก่อนแล้ว vuejs ค่อยไปลบ dom ทำให้ index เลื่อนจึงลบผิด dom ครับ

@update:title=”value => list.title = value” เมื่อมี event ชื่อ update:title เกิดขึ้นให้เอาค่าตัวแปร value ใส่เข้าไปใน list.title ส่วน event ชื่อ update:description ก็ทำเช่นเดียวกันโดยใส่ไปใน list.description โดย list แต่ละตัวจะมาจาก array lists ที่มี Object อยู่ข้างใน

:title and :description เป็นการส่ง props เข้าไปใน component FieldList.vue แบบปกติที่เราคุ้นเคย (ไม่ต้องส่งก็ได้ในกรณีที่เราไม่ต้องการ initial ค่าอะไรลงไปในตอนแรก)

<button type="button" class="btn-add" @click="addField">Add Field</button>

เมื่อกดปุ่มนี้จะเรียกฟังก์ชั่น addField

methods: {
    addField() {
      this.lists.push({ title: '', description: '' })
    }
  }
}

addField จะทำการ push array เข้าไปโดย initial ค่าเป็น Object ที่มี element เป็น title และ description เป็นค่าว่าง


<template>
  <div>
   <input type="text" :value="title" placeholder="Title" @input="updateValue($event.target.value, 'title')">
   <input type="text" :value="description" placeholder="Description" @input="updateValue($event.target.value, 'description')">
  </div>
</template>
<script>
export default {
props: ['title', 'description'],
  
  methods: {
    updateValue(value, type) {
     if (type === 'title') {
      this.$emit('update:title', value)
      return
     }
     this.$emit('update:description', value)
    }
  }
}
</script>

การทำงานแต่ละส่วนของไฟล์ FieldList.vue

props: ['title', 'description']

ทำการรับ props ที่ส่งเข้ามาและนำไปใส่ใน attribute value ของ input

<input type="text" :value="title" placeholder="Title" @input="updateValue($event.target.value, 'title')">
<input type="text" :value="description" placeholder="Description" @input="updateValue($event.target.value, 'description')">

@input=”updateValue($event.target.value, ‘title’)” เมื่อมีการพิมพ์ค่าใน input จะทำการเรียกฟังก์ชั่น updateValue ส่ง param เข้าไปใน function 2 ตัวคือ

$event เป็น event ของตัว vue ลอง console.log() ออกมาดูได้ครับสามารถเอาไปต่อยอดได้หลายอย่างเลยแต่ผมเข้าไปเอาข้อมูลแค่ target.value เพื่อเอาค่าจาก input เท่านั้น

type อันนี้เป็นการส่งไปบอกเฉยๆว่าให้ emmit update ตัวไหนกลับไปผมแค่ไม่อยากแยกฟังก์ชั่นเลยเขียน if เอาเพื่อเลือกการส่ง emit

methods: {
  updateValue(value, type) {
    if (type === 'title') {
     this.$emit('update:title', value)
     return
    }
    this.$emit('update:description', value)
   }
 }

ถ้า type เป็น title ก็ให้ emit update:title ตรงตัวเลยครับแล้วส่ง value กลับไป


เอาละมาถึงตอนสุดท้ายทุกครั้งที่เราพิมพ์ข้อมูลลงไป emit จะส่งค่ากลับไปเข้า object ตาม index ที่ได้ loop ไว้ครับทำให้ข้อมูลทั้งหมดไม่ทับกันซึ่งถ้าเราใช้ v-modal แบบปกติจะทำให้คืนค่ากลับมาทับกันไม่ได้แยกออกจากกันเป็นส่วนๆแบบนี้ มีรูปภาพประกอบ…

Result from tutorial

มาถึงตรงนี้แล้วหลายคนอ๋อแน่นอนว่าเห้ยมันทำแบบนี้ได้ด้วยซึ่งผมก็ไม่ได้คิดแบบนี้เหมือนกันครับตอนแรกว่าใช้ loop แล้วเอาแต่ละ index มาทำแบบนี้ต้องขอบคุณกลุ่ม Vue.js Thailand ที่มาสะกิตต่อมอยากรู้อยากเห็นของผมด้วย..

*** แก้ไขการส่ง :key เข้าไปใน component ในกรณีที่ใช้ v-for ในท่าประมานนี้ควรสร้าง index ขึ้นมารันเองนะครับคำอธิบายอยู่ด้านบนตรงไฟล์ TodoList.vue ครับ

ลิงค์ git ลอง clone ไปดูได้เลยครับ

Dark Mode

tutorial-two-way-binding-vuejs (this link opens in a new window) by anthoz69 (this link opens in a new window)

tutorial-two-way-binding-vuejs. This project will show you how to pass data from child to parent component.

Reference

https://vuejs.org/v2/guide/components.html#sync-Modifier
https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events
https://vuejs.org/v2/guide/components.html#Customizing-Component-v-model
https://www.facebook.com/groups/VuejsThailand/permalink/318354791957118/

เกี่ยวกับผู้เขียน

ITTHIPAT

สวัสดีครับผม อิทธิพัทธ์ (เป้) ชอบหาเทคนิคต่างๆที่ทำให้ชีวิต Programmer ง่ายขึ้น ทั้ง Automate, Library ชอบทำ Blog และ Video ถ้ามีเวลานะ!

ขอบคุณทุกคนที่ติดตาม และอ่านบทความของผมครับ ผมหวังว่าความรู้ที่เขียนขึ้นในเว็บไซต์นี้จะช่วยทุกท่านได้ไม่มากก็น้อย 

Scroll to Top