LoginSignup
14
11

More than 3 years have passed since last update.

v-modelのcomputedを動的に定義する方法

Last updated at Posted at 2019-12-29

オブジェクトをコンポーネントにバインドする時に困ったことがありました。
例えば以下の様な例で考えてみます。

この例ではコンテナ層とプレゼンテーション層でフォームデータをバインドしています。
今回はdataとしてpostFormオブジェクトを定義しており、項目数は2つです。

PostConatainer.vue
<script>

import Post from '../../components/Post/Post.vue'

export default {
  components:{
    Post,
  },
  data(){
    return {
      postForm:{
        name: null,
        photo: null
      }
    }
  },
  render: function(createElement){
    return createElement(Post,{
      props:{
        value: this.postForm
      },
      on: {
        "input" : ($event) => { this.postForm = $event },
      },
    })
  }

}

</script>

propsとして受け取ったPost.vueではフォーム項目をcomputedのプロパティとして定義しています。
でもこれ仮に項目数が100個に増えると、computedの定義も100個にしなければいけないと思いませんか?

Post.vue
<template>
  <div class="form">
    <el-form ref="form" label-width="120px">
      <el-form-item label="名前">
        <el-input v-model="name"></el-input>
      </el-form-item>
      <el-form-item label="写真">
        <el-input v-model="photo"></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>

export default {
  props:['value'],
  computed:{
    name:{
      get(){
        return this.value.name
      },
      set(val){
        this.$emit('input',{ ...this.value, name: val})
      }
    },
    photo:{
      get(){
        return this.value.photo
      },
      set(val){
        this.$emit('input',{ ...this.value, photo: val})
      }
    }
  }
}

</script>

解決策

vueのライフサイクルフックであるbeforeCreateでは算出プロパティを定義することができます。
今回$optionsを使用してカスタムプロパティを定義します。

Post.vue
<template>
  <div class="form">
    <el-form ref="form" label-width="120px">
      <el-form-item label="名前">
        <el-input v-model="name"></el-input>
      </el-form-item>
      <el-form-item label="写真">
        <el-input v-model="photo"></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>

export default {
  props:['value'],
  methods: {
    emitData(val) {
      this.$emit('input',{...this.value, ...val});
    },
  }, 
  beforeCreate() {
    [
      'name',
      'photo'
    ].forEach((key) => {
      this.$options.computed = 
        {...this.$options.computed,
          [key] : {
            get() {return this.value[key];},
            set(val) {this.emitData({ [key]: val });},
          }
        }
    });
  },
}
</style>

これで項目数が増えても、キーを足していくだけで追加することができます!。
本当はObject.keysでforEachしたかったですが、beforeCreateの段階ではthis.valueがundefinedとなりました。
これは改善したいので、方法があれば教えて頂きたいです。

14
11
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
14
11