Menu Close

Emitting Custom Events with Vue.js

We can emit events with Vue. Events are emitted by child components and are listened to by their parent components.

Emitted can have data that’s sent along with the event emission.

In this article, we’ll look at how to emit custom Vue events with $emit and listen to them in the parent component.

We can emit events in our child component and use the listen to the event and use the emitted data as follows:

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <Foo @foo="bar = $event"></Foo>
      <p>{{bar}}</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js

Vue.component("Foo", {
  methods: {
    emit() {
      this.$emit("foo", "bar");
    }
  },
  template: `<button @click='emit'>Emit</button>`
});

new Vue({
  el: "#app",
  data: {
    bar: ""
  }
});

In the code above, we defined a Foo component with an emit method that emits an event called foo with the payload 'bar'.

Then in our template, we attached a listener to the template where we referenced our Foo component.

This is where we have:

<Foo @foo="bar = $event"></Foo>

We display assigned item in:

<p>{{bar}}</p>

Then when we click Emit, the foo event is emitted with the value 'bar'.

'bar' is assigned to $event. Then it’s set to bar in the parent component and displayed.

Whatever name we set it to, it’ll be the event name that’s used to attach event listeners. There’s no transformation of the names.

Customizing Component v-model

v-model is shorthand for @input and :value together. We can change that since Vue 2.2.0 to make v-model listen to other event names and bind to different props.

We can add the model property to our component so that v-model can listen to the event name and pass in props with names that we specify.

For example, we can write:

Vue.component("Foo", {
  model: {
    prop: "checked",
    event: "change"
  },
  data() {
    return {
      checked: false
    };
  },
  template: `
  <div>
    <label>foo</label>
    <input
      type="checkbox"
      :checked="checked"
      @change="$emit('change', $event.target.checked)"
    >
  </div>
  `
});

new Vue({
  el: "#app",
  data: {
    bar: false
  }
});

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <Foo v-model="bar"></Foo>
      <p>{{bar}}</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

In the code above, we have:

model: {
    prop: "checked",
    event: "change"
}

to specify that the parent’s v-model directive in the parent listens to the change event and pass data for the checkbox into the checked prop.

Now we should see the value of the checkbox displayed in the p tag below the Foo component as we click the checkbox.

Conclusion

We can emit custom events with Vue with the $emit method. It takes the name of the event as the first argument, and the value we want to emit in the second argument.

Then we can listen to the event and get the payload in the parent component.

We can customize v-model by setting the prop that v-model passes the value to and then event it listens to from the child component to set the value of the specified model.

Posted in vue