We’ve been learning about how components and specifically single file components work in VueJs. In this tutorial, we’ll expand our learning about components in Vue by looking at how communication happens between components. Components in and of themselves are great as they set up reusable pieces of code where we can use all of the features VueJs provides. Now we want to build connections between those components so that actions in one component can update a different component in the application. We’ll focus on parent to child and child to parent communication in this tutorial.
Parent To Child Communication In Vue
To move data from a parent component to a child component in Vue we use something called props. ReactJS also uses a similar convention for sharing data. Props is short for “properties” and is referring to properties set from outside, such as from the parent component. In order to tell the vue child component that it will receive data from outside of it’s own instance, you need to set up the props
property in the Vue object of the child component. This property holds an array of strings, with each string representing a property which can be set from the parent. Note that props are strictly for one way communication from the parent to the child, and you do not want to try and change the value of a prop directly in the child component. Otherwise, you will get an error of something like “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.”
Parent Component Uses An Attribute Binding
In order to pass the data down from the Parent Component to the Child Component, we can now visit the parent component and set up an attribute binding which uses the same name as the prop from the child component. Note that we are inside the parent component, but we are rendering a child component using it’s custom tag of <child-card>. It is on this tag where we set up the bound attribute. Now, since we are using parentmessage
as the attribute name, then in the Child we will need props: [‘parentmessage’] as a prop. In our Parent we pass the data down using <child-card :parentmessage=”parentmessage”></child-card>.
ParentCard.vue
<template>
<div>
<div class="card m-2" style="width: 40rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<button @click="sendMessage" class="btn btn-info">Send Child A Message</button>
<child-card :parentmessage="parentmessage"></child-card>
</div>
</div>
</div>
</template>
<script>
import ChildCard from './ChildCard.vue';
export default {
components: {ChildCard},
data() {
return {
thecardtitle: 'Parent Component!',
parentmessage: ''
}
},
methods: {
sendMessage() {
this.parentmessage = '<b>Message From Parent:</b> Do Your Homework'
}
}
}
</script>
<style>
</style>
Child Component uses props
Object
So in this snippet below we have a Child component which has a prop setup and a string value of parentmessage
in it’s array. What this indicates is that parentmessage
can be set from the outside, or from the parent component. That is exactly what we are doing in the section above. The string name given for the prop, in our case parentmessage
must match the property name used in the template section of this component.
ChildCard.vue
<template>
<div>
<div class="card m-3" style="width: 25rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<p class="card-text" v-html="thecardbody"></p>
<div v-if="parentmessage" class="card-text alert alert-warning" v-html="parentmessage"></div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['parentmessage'],
data() {
return {
thecardtitle: 'Child Component!',
thecardbody: 'I\'m just a child.'
}
}
}
</script>
<style>
</style>
Parent To Child Communication Prop Demo
So let’s see this little bit of code in action. Below we have the rendered ParentCard.vue parent component, and a nested ChildCard.vue child component. In the child, we are using a v-if
to conditionally display an alert with a message from the parent. If there is no message, then we do not display the alert. So when the page first renders, the initial value of parentmessage
is just an empty string. We can see this in the data()
method of the Parent Component. That is why at first, the Child component does not display any alert message. However, if the user clicks the “Send Child A Message” button in the Parent component, then a sendMessage()
function triggers. This sets the parentmessage
variable to “<b>Message From Parent:</b> Do Your Homework”. Since this variable is bound to the child using :parentmessage="parentmessage"
, and the child component is accepting that value via props: [“parentmessage”], then the child component updates with the alert message of “Message From Parent: Do Your Homework”. Pretty cool!
Child To Parent Communication In Vue
What about going in the other direction? How can we communicate from a Child component to a Parent Component in VueJS? For this we can emit a custom event in the Child Component, and listen for that emitted event in the Parent Component. Let’s add a little bit of markup to our existing demo code to create a custom event.
The Child Emits a Custom Event
First off in the <template> section of the child component, we will add a click handler of @click=”ok” like so.
ChildCard.vue
<template>
<div>
<div class="card m-3" style="width: 25rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<p class="card-text" v-html="thecardbody"></p>
<div v-if="parentmessage" class="card-text alert alert-warning" v-html="parentmessage"></div>
<button v-if="parentmessage" @click="ok" class="btn btn-success">Ok</button>
</div>
</div>
</div>
</template>
What this says is that when we click the Ok button, we want to run a method named ok()
. Let’s set up that method to emit a custom event when it triggers. We pass a string of ‘finished’ to the $emit function. We can choose any name we like, but this makes sense in our case. We want to send a message from the child back to the parent that we are finished.
ChildCard.vue
<script>
export default {
props: ["parentmessage"],
data() {
return {
thecardtitle: "Child Component!",
thecardbody: "I'm just a child."
};
},
methods: {
ok() {
this.$emit('finished')
}
}
};
</script>
The Parent Listens For The Custom Event
Now we can move back up to the Parent component and where we make use of the <child-card> custom tag, we can now attach an event listener for our custom event using @finished=”finished”. This means we are going to want to run a finished()
function inside the Parent component. Both the custom listener and the function it triggers are highlighted here.
ParentCard.vue
<template>
<div>
<div class="card m-2" style="width: 40rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<button @click="sendMessage" class="btn btn-info">Send Child A Message</button>
<child-card :parentmessage="parentmessage" @finished="finished"></child-card>
</div>
</div>
</div>
</template>
<script>
import ChildCard from './ChildCard.vue';
export default {
components: {ChildCard},
data() {
return {
thecardtitle: 'Parent Component!',
parentmessage: ''
}
},
methods: {
sendMessage() {
this.parentmessage = '<b>Message From Parent:</b> Do Your Homework'
},
finished() {
this.parentmessage = ''
}
}
}
</script>
<style>
</style>
Child To Parent Communication Emit Event Demo
In this demo you first click the “Send Child A Message” button. That sends the message down to the child component, and it renders the message along with a new button. Now, we can click the “Ok” button, and it emits that custom ‘finished’ event. In the Parent, we were listening for that custom event and on hearing it we trigger the finished() function to set the parentmessage
back to an empty string. Finally, everything re renders and we are back to the starting point. Now we have the Parent sending messages to the Child and the Child responding as well as the Child sending messages to the Parent and the Parent responding. Cool!
Child To Parent Communication via Callback Function
There is another way to send a message back to the parent from the child if you don’t want to emit a custom event. What you could do is instead of defining the ok() method on the child, you can define it on the parent. Once it is defined on the parent, you can pass another prop from the parent to the child. So what we have here in the ParentCard.vue file is the ok() method defined and highlighted, and the binding on the <child-card> defined and highlighted.
ParentCard.vue
<template>
<div>
<div class="card m-2" style="width: 40rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<button @click="sendMessage" class="btn btn-info">Send Child A Message</button>
<child-card :parentmessage="parentmessage" :ok="ok" @finished="finished"></child-card>
</div>
</div>
</div>
</template>
<script>
import ChildCard from './ChildCard.vue';
export default {
components: {ChildCard},
data() {
return {
thecardtitle: 'Parent Component!',
parentmessage: ''
}
},
methods: {
sendMessage() {
this.parentmessage = '<b>Message From Parent:</b> Do Your Homework'
},
finished() {
this.parentmessage = ''
},
ok() {
this.finished()
}
}
}
</script>
<style>
</style>
Now we need to update our props
on the child component. What this does is enable the passing of a callback function from the parent to the child via props. We can set that up like so.
ChildCard.vue
<template>
<div>
<div class="card m-3" style="width: 25rem;">
<div class="card-body">
<h5 class="card-title" v-text="thecardtitle"></h5>
<p class="card-text" v-html="thecardbody"></p>
<div v-if="parentmessage" class="card-text alert alert-warning" v-html="parentmessage"></div>
<button v-if="parentmessage" @click="ok" class="btn btn-success">Ok</button>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['parentmessage', 'ok'],
data() {
return {
thecardtitle: "Child Component!",
thecardbody: "I'm just a child."
}
}
}
</script>
<style>
</style>
The interaction between the parent and child is the same as it was before when we were emitting a custom event. You can use whichever option seems easier to you, but it does seem that emitting a custom event is the more popular of the two ways to communicate from a child component to a parent component.
VueJs Parent Child Communication Summary
We learned a little bit about how VueJs Parent Child Communication happens in an application during our VueJS Form Component tutorial. In this tutorial, we simplified things by removing the Laravel backend and focusing specifically on a purely Vue environment where we studied how props are used to send information from a Parent to a Child, and how custom events are usually used to communicate from a Child to a Parent in VueJS.