Epitouille Epitouille - 1 year ago 86
Javascript Question

Synchronise a props in Vuejs

I try to synchronise a prop in Vue.js

I've a parent component that include a child component with a prop. When the prop changes in the parent, the prop is updated in the child and when the prop changes in the child, the parent is updated.

I started with this example:

The html where my component is mounted

<div>
<div id="app">
</div>
</div>


And the parent + child:

Vue.component('myinput', {
template: '<div><input v-model="mytext" /></div>',
props: ['text'],

data() {
return {
mytext: this.text
}
}
})

const vm = new Vue({
el: '#app',
template: '<div> <myinput :text="mytext"></myinput> <p> {{mytext}} </p></div>',

data() {
return {
mytext: "Hello World!"
}
}
});


Since I cannot mutate the props, I need a local copy.
https://codepen.io/anon/pen/mMJGZO?editors=1010

If I want my parent component to be updated when the child change, I need to do an $emit.

For that, I created a wrapper arround "mytext" in the child component:

computed: {
wrapperMyText: {
get() {
return this.mytext;
},
set(v) {
this.mytext = v;
this.$emit('update:text', v);
}
}


I use wrapperMyText in the model. Playground here: https://codepen.io/anon/pen/GvJYgm?editors=1011

Now, if I want the binding the other way (parent to child) I need to add watchers in the child.

watch: {
text(v) {
this.mytext = v;
}
},


https://codepen.io/anon/pen/ZJGqeN?editors=1011

In the example, I've only one prop, I need to create a watcher and a computed propertie. If I have 5 properties, I will need 5 watchers and 5 computed properties. That means the component code is polluated (too much code) with all this stuff. So my questions are:

This code is the standard pattern for sync a prop ?

Is it better in this case to use a Store (like vuex)?

Why to much code is necessary to do a simple case ?

After reflexions, it seems I'm trying to recode v-model with prop...

Answer Source

A single computed property will accomplish everything you are attempting.

Vue.component('myinput', {
   template: '<div><input v-model="wrapperMyText"></div>',
   props: ['text'],
   computed: {
     wrapperMyText: {
       get() { return this.text;},
       set(v) { this.$emit('update:text', v);}
     }
   }
})

Here is your updated pen.

So to answer your questions:

  1. This is a standard pattern.
  2. If you put the state in Vuex, your input component will no longer be re-usable.
  3. You don't need all that code.
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download