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

Yudai Hirano

Yudai Hirano

Apr 02, 2021

事前条件

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

処理

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

事後条件

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

ポイント

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

コード例

<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>
<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メソッドを持つことができ、入力を使ってオブジェクトの正しいキーを更新し、それを親に返すことができます。

参考・引用

https://www.drewtown.dev/post/using-vues-v-model-with-objects/

;