LoginSignup
0
0

More than 3 years have passed since last update.

【Vue.js】v-modelとオブジェクト〜親子1対1のデータフローでオブジェクトを扱う〜

Last updated at Posted at 2021-04-01

事前条件

  • 子コンポーネントに抽出したいオブジェクトやオブジェクトのリストがある。

処理

  • 子コンポーネント内でプロパティを変更してオブジェクト全体のコピーを親に送り返す。

事後条件

  • 変更されたオブジェクトが親コンポーネントに渡される。

ポイント

  • JavaScriptのオブジェクトは参照渡し。
  • オブジェクトを直接変更するとVueの親子イベントが回避されてしまう。
    • アプリケーションのトラブルシューティングが難しくなるので、これは避ける。
  • emit部分でobject spread syntax,computed property nameを使用する。
    • 前出の問題を避け、親子1対1のデータフローに出来る

コード例

App.vue
<template>
  <section class="section">
    <div class="container">
      <h1 class="title is-size-2">Using Vue's v-model with complex objects</h1>
      <div v-for="(item, i) in holidays" :key="i">
        <h2 class="is-size-4">{{item.name}}</h2>
        <Child v-model="holidays[i]"/>
      </div>
      {{JSON.stringify(holidays)}}
    </div>
  </section>
</template>

<script>
import Child from "./components/Child";

export default {
  name: "App",
  components: {
    Child
  },
  data() {
    return {
      holidays: [
        {
          name: "Fourth Of July",
          date: null,
          description: ""
        },
        {
          name: "Thanksgiving",
          date: null,
          description: ""
        }
      ]
    };
  }
};
</script>
Child.vue
<template>
  <div>
    <div class="field">
      <div class="control">
        <label for="name" class="label">Name</label>
        <input class="input" :value="value.name" @input="updateValue('name', $event.target.value)">
      </div>
    </div>
    <div class="field">
      <div class="control">
        <label for="date" class="label">Date</label>
        <input
          class="input"
          type="date"
          :value="value.date"
          @input="updateValue('date', $event.target.value)"
        >
      </div>
    </div>
    <div class="field">
      <div class="control">
        <label for="textarea" class="label">Textarea</label>
        <textarea
          class="textarea"
          :value="value.description"
          @input="updateValue('description', $event.target.value)"
        />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: Object,
      required: true
    }
  },
  methods: {
    updateValue(key, value) {
      this.$emit("input", { ...this.value, [key]: value });
    }
  }
};
</script>

最も重要な部分は emit イベントの処理です。標準的なinputイベントをemitしたいのですが、今回のvalueは特別なもの(=オブジェクト)になります。

UpdateValueメソッドは、このコード { ...this.value, [key]: value } によって、新しいオブジェクトの値をemitします。ここでは、コードを非常にきれいに保つために、2つのJavaScriptの機能を使用します。
1つ目は、propを介して渡されたオブジェクトをコピーし、更新されたキー/値をオブジェクトにマージする、object spread syntaxです。

2つ目は、computed property name を使用することで、変数keyをオブジェクト内のキーの名前として使用することができます。これにより、パラメータとしてキーと値を受け取る汎用のupdateValueメソッドを持つことができ、入力を使ってオブジェクトの正しいキーを更新し、それを親に返すことができます。

参考・引用

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0