[Vuejs]-Updating a prop inside a child component so it updates on the parent container too

4👍

One solution:

simulate v-model

As Vue Guide said:

v-model is essentially syntax sugar for updating data on user input
events, plus special care for some edge cases.

The syntax sugar will be like:

the directive=v-model will bind value, then listen input event to make change like v-bind:value="val" v-on:input="val = $event.target.value"

So the steps:

  1. create one prop = value which you’d like to sync to parent component

  2. inside the child component, create one data porperty=internalValue, then uses Watcher to sync latest prop=value to data property=intervalValue

  3. if intervalValue change, emit one input event to notice parent component

Below is one simple demo:

Vue.config.productionTip = false
Vue.component('container', {
  template: `<div>
              <p><button @click="changeData()">{{value}}</button></p>
             </div>`,
  data() {
    return {
      internalValue: ''
    }
  },
  props: ['value'],
  mounted: function () {
    this.internalValue = this.value
  },
  watch: {
    value: function (newVal) {
      this.internalValue = newVal
    }
  },
  methods: {
    changeData: function () {
      this.internalValue += '@'
      this.$emit('input', this.internalValue)
    }
  }
})

new Vue({
  el: '#app',
  data () {
    return {
      items: ['a', 'b', 'c']
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <div>
    <p>{{items}}
    <container v-for="(item, index) in items" :key="index" v-model="items[index]">
    </container>
  </div>
</div>

or use other prop name instead of value (below demo use prop name=item):

Also you can use other event name instead of event name=input.

other steps are similar, but you have to $on the event then implement you own handler like below demo.

Vue.config.productionTip = false
Vue.component('container', {
  template: `<div>
              <p><button @click="changeData()">{{item}}</button></p>
             </div>`,
  data() {
    return {
      internalValue: ''
    }
  },
  props: ['item'],
  mounted: function () {
    this.internalValue = this.item
  },
  watch: {
    item: function (newVal) {
      this.internalValue = newVal
    }
  },
  methods: {
    changeData: function () {
      this.internalValue += '@'
      this.$emit('input', this.internalValue)
      this.$emit('test-input', this.internalValue)
    }
  }
})

new Vue({
  el: '#app',
  data () {
    return {
      items: ['a', 'b', 'c']
    }
  },
  methods: {
    syncChanged: function (target, index, newData) {
      this.$set(target, index, newData)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <div>
    Event Name=input
    <p>{{items}}</p>
    <container v-for="(item, index) in items" :key="index" :item="item" @input="syncChanged(items, index,$event)">
    </container>
  </div>
  <hr> Event Name=test-input
    <container v-for="(item, index) in items" :key="index" :item="item" @test-input="syncChanged(items, index,$event)">
    </container>
</div>
👤Sphinx

3👍

I usually use vuex to manage variables that I will be using in multiple components and like the error says, load them in the various components using the computed properties. Then use the mutations property of the store object to handle changes

In component files

computed: {
    newProfile: {
      get() {
        return this.$store.state.newProfile;
      },
      set(value) {
        this.$store.commit('updateNewProfile', value);
      }
    },

In the vuex store

state: {
    newProfile: {
      Name: '',
      Website: '',
      LoginId: -1,
      AccountId: ''
    }
},
mutations: {
    updateNewProfile(state, profile) {
      state.newProfile = profile;
    }
}

Leave a comment