This post will introduce you to how data and its state can be passed from a child component to its parent component in Vue.js using event emitters.

Before you start…

This post is suited for developers of all stages, including beginners. Here are a few things you should already have before going through this article:

Node.js version 10.x and above installed. You can verify whether you do by running the command below in your terminal/command prompt: node -v

A code editor — I highly recommend Visual Studio Code

Vue’s latest version, installed globally on your machine

Vue CLI 3.0 installed on your machine. To do this, uninstall the old CLI version first: npm uninstall -g vue-cli Then, install the new one: npm install -g @vue/cli

Download a Vue starter project here

Unzip the downloaded project

Navigate into the unzipped file and run the command below to keep all the dependencies up to date: npm install

Passing data through components

To pass data values from parent components (like the app.vue ) to child components (like nested components) inside the app component, Vue.js provides us with a platform called props. Props can be called custom attributes you can register on a component that let you define data in the parent component, give it a value, and then pass the value to a prop attribute that can then be referenced down in the child components.

This post will show you the reverse of this process. To pass down and update data values in a parent component from the child component in such a way that all other nested components will be updated, too, we use the emit construct to handle event emission and updating of data.

Demo

You will be taken through the process of emitting events from a child component, setting up listening on the parent component in order to pass data from the child component, and then finally updating the data value.

If you followed this post from the start, you will have downloaded and opened the starter project in VS Code. The project is the finished, complete code to this post here.

The reason behind having that as a starter project is so that you can play around with the props concept before getting introduced to reversing the process.

Getting started

In the folder, you will find two child components: test.vue and test2.vue , with the parent component being the app.vue file. We will use the headers of the two child components to illustrate this event emission approach. Your Test.vue file should look like this:

<template> <div> <h1>Vue Top 20 Artists</h1> <ul> <li v-for="(artist, x) in artists" :key="x"> <h3>{{artist.name}}</h3> </li> </ul> </div> </template> <script> export default { name: 'Test', props: { artists: { type: Array } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> li{ height: 40px; width: 100%; padding: 15px; border: 1px solid saddlebrown; display: flex; justify-content: center; align-items: center; } a { color: #42b983; } </style>

To make the header receive the title from an implicit definition in the data property section, you create the data section and add the definition, and then add the interpolation symbol in the template, like this:

<template> <div> <h1>{{header}}</h1> <ul> <li v-for="(artist, x) in artists" :key="x"> <h3>{{artist.name}}</h3> </li> </ul> </div> </template> <script> export default { name: 'Test', props: { artists: { type: Array } }, data() { return { header: 'Vue Top Artists' } } } </script>

If you run the application, you get exactly the same interface you got right at the start. The next step is to change this defined property on click.

Toggling the header

To toggle the header, you will have to add an event listener on click to the header and specify the function that will contain the logic that should happen when it is clicked.

<template> <div> <h1 v-on:click="callingFunction">{{header}}</h1> <ul> <li v-for="(artist, x) in artists" :key="x"> <h3>{{artist.name}}</h3> </li> </ul> </div> </template> <script> export default { name: 'Test', props: { artists: { type: Array } }, data() { return { header: 'Vue Top Artists' } }, methods: { callingFunction(){ this.header = "You clicked on header 1"; } } } </script>

Now your header changes to the string inside the calling function on click.

Setting the emitter

At this stage, you want to pass on this same behavior to the parent component so that on click, every title nested in the parent component changes.

To do this, you will create an emitter that will emit an event in the child component that the parent component can listen to and react (this is just the same as event listener logic for components).

Change the script section in the Test.vue file to the code block below:

<script> export default { name: 'Test', props: { artists: { type: Array }, header: { type: String } }, data() { return { // header: 'Vue Top Artists' } }, methods: { callingFunction(){ // this.header = "You clicked on header 1" this.$emit('toggle', 'You clicked header 1'); } } } </script>

Here, the type of data expected of the header was defined as a prop. Then, in the method, there is an emit statement that tells Vue to emit an event (just like any other — e.g., a click event) on toggle and pass the string as an argument. This is all you need to set up an event that will be listened to inside another component.

Listening to the emitted event

Now the next thing to do after an event is created is to listen and respond to it. Copy this code block into your app.vue file:

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <Test v-bind:header="header" v-on:toggle="toggleHeader($event)" /> <Test v-bind:artists="artists" /> <test2 v-bind:header="header"/> <test2 v-bind:artists="artists" /> </div> </template> <script> import Test from './components/Test.vue' import Test2 from './components/Test2' export default { name: 'app', components: { Test, Test2 }, data (){ return { artists: [ {name: 'Davido', genre: 'afrobeats', country: 'Nigeria'}, {name: 'Burna Boy', genre: 'afrobeats', country: 'Nigeria'}, {name: 'AKA', genre: 'hiphop', country: 'South-Africa'} ], header: 'Vue Top Artists' } }, methods: { toggleHeader(x){ this.header = x; } } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>

In the template section, you can see that the first component, Test , has two Vue directives on it. The first is the v-bind , which binds the initial header property to the implicit definition in the data object under the artists array; on initialization, the string Vue Top Artists is shown.

The second directive is the v-on , which is for listening to events; the event to listen to is toggle (remember, you already defined it in the Test component), and the calling function on it is the toggleHeader . This function is created, and the string from the child component is passed through the $event argument to display here.

The implication

This passes data through the emitter to the parent component, and so because other components are nested in the parent component, the data in every one of the nested components re-renders and updates. Go into the test2.vue file and copy this code block into it:

<template> <div> <h1>{{header}}</h1> <ul> <li v-for="(artist, x) in artists" :key="x"> <h3>{{artist.name}} from {{artist.country}}</h3> </li> </ul> </div> </template> <script> export default { name: 'Test2', props: { artists: { type: Array }, header: { type: String } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> li{ height: 40px; width: 100%; padding: 15px; border: 1px solid saddlebrown; display: flex; justify-content: center; align-items: center; } a { color: #42b983; } </style>

Here, the data interpolation was set and specified to be a string in the props object. Run the application in your development server:

npm run serve

You see that once the event is reacted to in the parent component, all the components updated their header even though the definition was specified in just one child component.

You can find the complete code for this tutorial here on GitHub.

Conclusion

You can see another interesting side of using events in Vue with emitters: you can now create an event in one component and listen to and also react to it in another component. This can have many use cases that will be really beneficial in your workflow — happy hacking!

Experience your Vue apps exactly how a user does Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, https://logrocket.com/signup/ Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket LogRocket is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred. Modernize how you debug your Vue apps - Start monitoring for free.