1

I want to change the parent's prop's value from a child component. This works great in vuejs 1 but not in vue 2 (I want to use it in vue.js 2).

Here is a small example :

HTML

<div id="app">
   <parent :content="{value:'hello parent'}"><</parent>
</div>

JavaScript

var parent = {
  template: '<child :content="content"></child>',
  props: ['content'],
};

var child = {
  template: '<div>{{ content.value }}<button @click="change">change me</button></div>',
  props: ['content'],
  methods: {
    change() {
      this.content.value = "Value changed !";
    }
  }
};

Vue.component('child', child);
Vue.component('parent', parent);

new Vue({
  el: '#app',
});

https://jsfiddle.net/f5gt94f2/

2 Answers 2

3

tl;dr: in vue2, you need to use the .sync modifier.


Create a local copy of the content prop in the parent's data (see reason here).

var parent = {
  ...
  data() {
    return {
      localContent: this.content // creating a local copy, so we can mutate and react to it
    }
  }
};

Now, pass that localContent to the child, not content. And pass it using .sync so it can be updated:

var parent = {
  template: '<div><child :content.sync="localContent"></child></div>',
  ...                     //     ^^^^^^^^^^^^^^^^^^^^-- changed here

Now, in the child, don't assign to this.content.value, emit an update event instead:

var child = {
    ...
    change() {
      this.$emit('update:content', {value: "Value changed !"})
    }
  }
};

This event, with the new value, will be picked up by the parent and will update its localContent which also will, in consequence, update the child's content prop.

Final running code below.

var parent = {
  template: '<div><child :content.sync="localContent"></child><br>At parent: {{ localContent }}</div>',
  props: ['content'],
  data() {
    return {
      localContent: this.content
    }
  }
};

var child = {
  template: '<div>At child: {{ content.value }}<button @click="change">change me</button></div>',
  props: ['content'],
  methods: {
    change() {
      this.$emit('update:content', {value: "Value changed !"})
    }
  }
};

Vue.component('child', child);
Vue.component('parent', parent);

new Vue({
  el: '#app'
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>

<div id="app">
  <parent :content="{value:'hello parent'}"></parent>
</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Excellent ! I didn't know that .sync is back again, I also can use this.content.value = "helloooo"; instead of this.$emit('update:content', {value: "Value changed !"}) and it works
You can, but you shouldn't, it is sort of a bad practice. And it only works because value is a nested property, and because it is reactive (due to being a data property in the parent). The content that arrives at the parent is not reactive, for example, because it was passed via a literal <parent :content="{value:'hello parent'}">. But, anyway, if you are aware of the drawbacks, but think changing directly is worth it (I can understand that), then you can use it, or course.
1

You will have to use emit events for this

Parent:

<child :content="content" @updateParent="updateValue"></child>

methods: {
  updateValue (value) {
    // Your code here
  }
}

Child:

props: ['content'],
methods: {
  change () {
    this.$emit('updateParent', value)
  }
}

https://v2.vuejs.org/v2/guide/components.html#Custom-Events

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.