One thing that often confuses people when first starting out with Vue is transmitting events from the child to the parent. Most of this confusion occurs because this.$emit() emits the event on to the child vue instance itself, so you cannot retrieve it in the parent using this.$on(), so how do you get the event from the child to the parent?

Actually, it’s quite straightforward, you attach the event to the component in the parent and use that to call a parent method. To better illustrate that let’s first look at what an event is.

Using v-on

You’re probably using events all the time by doing something like v-on:click="doSomething" (or @click="doSomething" when using the shorthand). When you use $emit() you are creating a custom event that can be used just like click, and this is the key to child parent communication. As an example, let’s create a component that sends a message from the child to the parent. First let’s create the child component, that sends the message when we click a button:

Template:

<template>
  <div>
    <input v-model="message"> <button @click="sendMessage">Send Message</button>
  </div>
</template>

Vue Instance:

  methods: {
    sendMessage(){
      this.$emit('send-message',this.message);
    }
  },
  data(){
    return {
     message: ''
    }
  }

With this component we can type a message, and when we click the “send message” button the sendMessage() method emits an event called send-message, which we can now listen to on the component itself. So, in our parent we can do:

<message @send-message="updateMessage"></message>

We just need to create an updateMessage method, to update the message in the parent:

methods:{
  updateMessage(message){
	this.message = message
  }
},
data(){
  return{
    message: ''
  }
}

Now when you click the “Send Message” button, the event is emitted, captured on the component in the parent and updated via the parent’s updateMessage() method. You can see this in action in this JSFiddle: https://jsfiddle.net/vuetiful/9td2a80e/

Passing Parameters

One thing you may have noticed in the above code is that I didn’t explicitly pass the message parameter from the event on the component to the updateMethod. This is because Vue automatically passes the parameters to your method. In fact you can emit multiple parameters and Vue will pass them to your method automatically, as long as you declare them in the method definition:

Child

this.$emit('send-names', firstname, surname)

Parent

HTML
<names @send-names="updateName"></names>
Vue Instance
updateName(firstname, surname){
	this.name = firstname + ' ' + surname;
}

Here the child has emitted a first name and a surname. Because I have declared them in my updateName method, Vue automatically passes the parameters for me, here’s the JSFiddle: https://jsfiddle.net/vuetiful/zf6ooym4/

Gotchas

Why isn’t my event being captured?

One thing to watch out for is custom event names, if you are using in-dom templates then you cannot use camelCase for the event name, either use lowercase or kebab-case:

this.$emit('send-message', this.message) // OK
this.$emit('sendmessage', this.message) // OK
this.$emit('sendMessage', this.message) // This won't fire on the parent.

Remember this is for in dom templates only i.e. you are using the template tag and using template: "#my-template" in your component. String templates and single file components are not affected by this restriction.

Advertisements