Vue.js component with v-shaped model

I was able to achieve sibling v-model 2-way binding for the custom component, but need to make it one level deeper.

Current working code:

    <template lang="html">

      <div class="email-edit">

        <input ref="email" :value="value.email" @input="updateInput()"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

      </div>

    </template>
    <script type="text/javascript">
      import LineEditor from './LineEditor.vue'
      export default {
        components: {
          LineEditor
        },
        computed: {
        },
        methods: {
          updateInput: function(){
            this.$emit('input',{
              email: this.$refs.email.value,
              body: this.$refs.body.value
            })
          }
        },
        data: function(){
          return {}
        },
        props: {
          value: {
            default: {
              email: "",
              body: ""
            },
            type:Object
          }
        }
      }
    </script>

      

Used like this: <email-edit-input v-model="emailModel" />

However, if I add this part, the value no longer propagates upward:

      <div class="email-edit">

        <line-editor ref="email" :title="'Email'" :value="value.email" @input="updateInput()"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

      </div>

    </template>
    <script type="text/javascript">
      import LineEditor from './LineEditor.vue'
      export default {
        components: {
          LineEditor
        },
        computed: {
        },
        methods: {
          updateInput: function(){
            this.$emit('input',{
              email: this.$refs.email.value,
              body: this.$refs.body.value
            })
          }
        },
        data: function(){
          return {}
        },
        props: {
          value: {
            default: {
              email: "",
              body: ""
            },
            type:Object
          }
        }
      }
    </script>

      

Using this second custom component:

<template lang="html">

  <div class="line-edit">
    <div class="line-edit__title">{{title}}</div>
    <input class="line-edit__input" ref="textInput" type="text" :value="value" @input="updateInput()" />
  </div>

</template>
<script type="text/javascript">
  export default {
    components: {
    },
    computed: {
    },
    methods: {
      updateInput: function(){
        this.$emit('input', this.$refs.textInput.value)
      }
    },
    data: function(){
      return {}
    },
    props: {
      title:{
        default:"",
        type:String
      },
      value: {
        default: "",
        type: String
      }
    }
  }
</script>

      

The first block of code works fine with input only. However, the use of two custom components doesn't seem to flow over both components, but only to the LineEditor. How do I get these values ​​to bubble through all custom components, regardless of nesting?

+3


source to share


2 answers


I've updated my code a bit to handle the v-model on your components so that you can pass values ​​through the tree as well as create tree backups. I've also added observers to your components so that if you have to update the value of an email object outside of the email editor component, the updates will be reflected in the component.

console.clear()

const LineEditor = {
  template:`
    <div class="line-edit">
      <div class="line-edit__title">{{title}}</div>
      <input class="line-edit__input" type="text" v-model="email" @input="$emit('input',email)" />
    </div>
  `,
  watch:{
    value(newValue){
      this.email = newValue
    }
  },
  data: function(){
    return {
      email: this.value
    }
  },
  props: {
    title:{
      default:"",
      type:String
    },
    value: {
      default: "",
      type: String
    }
  }
}

const EmailEditor = {
  components: {
    LineEditor
  },
  template:`
    <div class="email-edit">
      <line-editor :title="'Email'" v-model="email" @input="updateInput"/>
      <input :value="value.body" v-model="body" @input="updateInput"/>
    </div>
  `,
  watch:{
    value(newValue){console.log(newValue)
      this.email = newValue.email
      this.body = newValue.body
    }
  },
  methods: {
    updateInput: function(value){
      this.$emit('input', {
        email: this.email,
        body: this.body
      })
    },
  },
  data: function(){
    return {
      email: this.value.email,
      body: this.value.body
    }
  },
  props: {
    value: {
      default: {
        email: "",
        body: ""
      },
      type: Object
    }
  }
}

new Vue({
  el:"#app",
  data:{
    email: {}
  },
  components:{
    EmailEditor
  }
})
      

<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <email-editor v-model="email"></email-editor>
  <div>
    {{email}}
  </div>
  <button @click="email={email:'testing@email', body: 'testing body' }">change</button>
</div>
      

Run codeHide result




In the above example, entering values ​​on the inputs updates the parent. In addition, I added a button that changes the parent value to simulate the value changing outside of the component and changes that are reflected in the components.

There is no real reason to use it ref

at all for this code.

+3


source


In my case, manual walkthrough done on both components did not work. However, replacing my first custom component, follow these steps:

<line-editor ref="email" :title="'Email'" v-model="value.email"/>
<input ref="body" :value="value.body" @input="updateInput()"/>

      



Using only the v-model in the first component and then allowing the second custom component to emit upwards did the trick.

0


source







All Articles