Vuejs updates parent data from child component

I am starting to play with vujs (2.0). I built a simple page with one component. There is one instance of Vue with data on the page. On this page, I registered and added the component in HTML. The component has one input[type=text] . I want this value to be reflected on the parent (main instance of Vue).

How to update parent component data correctly? The transfer of the attached attribute from the parent is unsuitable and issues some warnings to the console. They have something in their document, but that does not work.

+87
javascript vue-component
source share
7 answers

Bilateral binding in Vue 2.0 is deprecated in favor of a more event-driven architecture. In general, a child should not mutate his details. Rather, it should $emit events and allow the parent to respond to these events.

In your specific case, you can use a custom component with v-model . This is a special syntax that allows something close to two-way binding, but it is actually a shorthand for the event-driven architecture described above. You can read about it here β†’ https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events .

Here is a simple example:

 Vue.component('child', { template: '#child', //The child has a prop named 'value'. v-model will automatically bind to this prop props: ['value'], methods: { updateValue: function (value) { this.$emit('input', value); } } }); new Vue({ el: '#app', data: { parentValue: 'hello' } }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script> <div id="app"> <p>Parent value: {{parentValue}}</p> <child v-model="parentValue"></child> </div> <template id="child"> <input type="text" v-bind:value="value" v-on:input="updateValue($event.target.value)"> </template> 

Documents claim that

 <custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input> 

equivalently

 <custom-input v-model="something"></custom-input> 

This is why the support for the child needs to be named by value, and why the child needs an $ emit event called input .

+123
source share

From the documentation :

In Vue.js, the relationships of parent and child components can be generalized as props, up events. The parent passes the data to the child through the details, and the child sends messages to the parent through the events. Let's see how they work next.

enter image description here

How to transfer props

Below is the code for transferring details to a child element:

 <div> <input v-model="parentMsg"> <br> <child v-bind:my-message="parentMsg"></child> </div> 

How to create an event

HTML:

 <div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> 

JS:

 Vue.component('button-counter', { template: '<button v-on:click="increment">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { increment: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) 
+92
source share

In the child component: this.$emit('eventname', this.variable)

In the parent component:

 <component @eventname="updateparent"></component> methods: { updateparent(variable) { this.parentvariable = variable } } 
+21
source share

I agree with the answers about events and the V-model for those above. However, I thought I would post what I found about components with several form elements that want to send back to their parents, as this seems to be one of the first articles returned by Google.

I know that the question indicates a single input, but this seems like the closest match and can save people some time with similar vue components. Also, no one has mentioned the .sync modifier .sync .

As far as I know, the v-model solution is suitable for only one input returned to their parent. I spent a little time searching for it, but the Vue documentation (2.3.0) really shows how to synchronize several details sent to the component to the parent (of course, via emit).

It is accordingly called the .sync modifier.

This is what the documentation says:

In some cases, we may need a β€œtwo-way snap” for support. Unfortunately, true two-way binding can create maintenance problems because child components can mutate the parent, and the source of this mutation will not be obvious in both the parent and the child.

Therefore, instead we recommend generating events in the update:myPropName . For example, in a hypothetical component with the title we could report the intention to assign a new value with:

 this.$emit('update:title', newTitle) 

The parent can then listen to this event and update the local data property if it wants to. For example:

 <text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" ></text-document> 

For convenience, we offer an abbreviation for this template with the .sync modifier:

 <text-document v-bind:title.sync="doc.title"></text-document> 

You can also synchronize several at the same time, sending through an object. Check the documentation here

+4
source share

Child component

Use this.$emit('event_name') to send the event to the parent component.

enter image description here

Parent component

To listen to this event in the parent component, we do v-on:event_name and the method ( ex. handleChange ) ex. handleChange that we want to execute for this event.

enter image description here

Done :)

+4
source share

It is also possible to pass details as an object or an array. In this case, the data will be two-way connected:

(This is noted at the end of the topic: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow )

 Vue.component('child', { template: '#child', props: {post: Object}, methods: { updateValue: function () { this.$emit('changed'); } } }); new Vue({ el: '#app', data: { post: {msg: 'hello'}, changed: false }, methods: { saveChanges() { this.changed = true; } } }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script> <div id="app"> <p>Parent value: {{post.msg}}</p> <p v-if="changed == true">Parent msg: Data been changed - received signal from child!</p> <child :post="post" v-on:changed="saveChanges"></child> </div> <template id="child"> <input type="text" v-model="post.msg" v-on:input="updateValue()"> </template> 
+3
source share

An easier way is to use this.$emit

Father.vue

 <template> <div> <h1>{{ message }}</h1> <child v-on:listenerChild="listenerChild"/> </div> </template> <script> import Child from "./Child"; export default { name: "Father", data() { return { message: "Where are you, my Child?" }; }, components: { Child }, methods: { listenerChild(reply) { this.message = reply; } } }; </script> 

Child.vue

 <template> <div> <button @click="replyDaddy">Reply Daddy</button> </div> </template> <script> export default { name: "Child", methods: { replyDaddy() { this.$emit("listenerChild", "I'm here my Daddy!"); } } }; </script> 

My complete example: https://codesandbox.io/s/update-parent-property-ufj4b

0
source share

All Articles