28

I have a component and i am passing value 543 to props :prop-room-selected,

<navigation-form :prop-room-selected='543'>
</navigation-form>

Now, From a button click, i am calling the function updateCoachStatus to change the value of propRoomSelected, but the props value is not updating.

{
    template: '#navigation-form',
    props: ['propRoomSelected'],
    data: function () {
      return {
        roomSelected: this.propRoomSelected,
      }
  },
  methods:{
      updateCoachStatus: function(event){
         this.propRoomSelected = 67;
      }
  }
}

I dont know how to change the value of props from function. Is it possible in Vue to update the value of props??

Rubanraj Ravichandran
  • 1,213
  • 2
  • 17
  • 26
  • is it true that if the data in child component is in an `` tag, the emit and update can be omitted? I'm asking because I'm copying the props to local and mutate the local by v-model in an ``, the props got automatically updated. – Dacredible Jan 18 '19 at 00:50
  • How are you copying the data? Are you doing clone or deepClone, else just assigning the prop value to data in your child component? If you do assign prop value directly to child component data, then the local data still have the reference of parent data. So, technically it will update the prop data too. – Rubanraj Ravichandran Jan 18 '19 at 14:23

3 Answers3

45

What you are doing will throw a warning in Vue (in the console).

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "propRoomSelected"

The value will actually change inside the component, but not outside the component. The value of a parent property cannot be changed inside a component, and, in fact, the updated value will be lost if the parent re-renders for any reason.

To update the parent property, what you should do is $emit the updated value and listen for the change in the parent.

Vue.component("navigation-form",{
    template: '#navigation-form',
    props: ['propRoomSelected'],
    data: function () {
      return {
        roomSelected: this.propRoomSelected,
      }
  },
  methods:{
      updateCoachStatus: function(event){
         this.$emit("update-room-selected", 67) ;
      }
  }
})

And in your parent template listen for the event

<navigation-form :prop-room-selected='propRoomSelected'
                 @update-room-selected="onUpdatePropRoomSelected">
</navigation-form>

Here is an example.

This is a common pattern and Vue implemented a directive to make it slightly easier called v-model. Here is a component that supports v-model that will do the same thing.

Vue.component("navigation-form-two",{
    template: '#navigation-form-two',
    props: ['value'],
    data: function () {
      return {
        roomSelected: this.value,
      }
  },
  methods:{
      updateCoachStatus: function(event){
         this.$emit("input", 67) ;
      }
  }
})

And in the parent template

<navigation-form-two v-model="secondRoomSelected">
</navigation-form-two>

Essentially, for your component to support v-model you should accept a value property and $emit the input event. The example linked above also shows that working.

Bilal
  • 3,191
  • 4
  • 21
  • 49
Bert
  • 80,741
  • 17
  • 199
  • 164
  • 1
    what if I need to update 3 or more properties, I need to create a method for each property and handle each one separately or there's a better approach? – carmolim Sep 15 '21 at 19:46
  • You could either put those 3 properties in one object and have you child component return this updated object or bind all 3 properties seperately but as "once" using `:v-bind="{prop1: "xxx", ...}"` on the child component. – nonNumericalFloat Aug 05 '22 at 13:55
2

Another approach is using a computed property for handling props:

{
  template: '#navigation-form',
  props: ['propRoomSelected'],
  data () {
    return {
      roomSelected: this.computedRoomSelected,
      changeableRoomSelected: undefined
    }
  },
  computed: {
    computedRoomSelected () {
      if (this.changeableRoomSelected !== undefined) {
        return this.changeableRoomSelected
      }
      return this.propRoomSelected
    }
  },
  methods: {
    updateCoachStatus (event) {
      this.changeableRoomSelected = 67
    }
  }
}
Ilyich
  • 4,966
  • 3
  • 39
  • 27
0

Vue props are one way data flow, We should not overwrited the props value. It's not a recommended way. Please refer the attached screen shot. enter image description here

for more info: https://vuejs.org/guide/components/props.html#one-way-data-flow