Tutorial

Introduction to Vue Custom Events

Published on March 27, 2020
author

Parthiv Mohan

Introduction to Vue Custom Events

We know that Vue can listen to events on your elements and trigger specific functions to run when such events occur. Vue.js also allows you to listen for custom events, an ability which has its most important use case in allowing child components to fire off events that parent components can listen for.

We created a simple photo gallery component in the Vue Template Syntax article. You could click any of the photos in a row of thumbnails and the photo you clicked would be displayed in a large size below. Now, what if we wanted the background of the entire page to be set to the average color of the photo being displayed? We could call this something like theater mode.

The power of custom events is that we can fairly easily do that. The parent component of the photo gallery, App.vue, simply needs to receive the average RGB value of the photo from its child component, PhotoGallery.vue, when the photo is clicked.

Let’s get started. This tutorial picks up where the Template Syntax tutorial left off.

App Setup

Let’s use the same setup from this previous post.

Let’s Write Some Custom Event Code

We’re going to use an npm library called fast-average-color to get the average color value for a particular photo. Import it at the top of the <script> section of PhotoGallery.vue.

import from 'fast-average-color';

Our PhotoGallery.vue component, currently, has a method, highlight(), which is triggered when you click on one of the photos.

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
}

This method displays the clicked photo in a larger size below the thumbnails. Notice that we used event.target all over the method. event.target is the element that was clicked on. This is the image that we want to get the average color of.

By perusing the fast-average-color docs, we can find the getColorAsync function, which returns a color object where color.rgba is the average RGB value. Let’s go ahead and make that function call.

const fac = new FastAverageColor();

fac.getColorAsync(event.target)
  .then(function(color) {
  })
  .catch(function(e) {
    console.log(e);
  });

We’re not yet doing anything with color. Ultimately, we need to set the background color to color.rgba in App.vue. App.vue is going to have a method that takes color.rgba as an argument. Why don’t we just go ahead and write that method?

methods: {
  setBackground(rgba) {
    document.querySelector('body').style.backgroundColor = rgba;
  }
}

That should look good to you!

Take a look at the template section of App.vue. Here’s how it looks right now:

<template>
  <div id="app">
    <PhotoGallery />
  </div>
</template>

The App component is going to have to pick up an event from the PhotoGallery component, a custom event. Say the event was called theater-mode; when we want to listen for such an event in our component, the syntax is just like for regular events. That is, it would be: v-on:theater-mode. When theater-mode occurs we’ll call our setBackground method.

Now we need to send the value color.rgba to App.vue somehow. Go back to PhotoGallery.vue.


Every Vue component has a method $emit. This method allows you to trigger an event, in our case one called theater-mode. We’re going to call this.$emit inside the then function from the async call we made to the color library. Let’s jog your memory.

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
  const fac = new FastAverageColor();
  fac.getColorAsync(event.target)
    .then(function(color) {
    })
    .catch(function(e) {
      console.log(e);
    });
}

this.$emit takes the event name as its first argument and has optional further arguments in which you can pass data. We’ll pass color.rgba. So our function call is going to look like this.$emit('theater-mode', color.rgba). Here’s our new function:

highlight() {
  event.target.id = "theater";
  this.theatrical = event.target.src;
  let eventIterator = event.target.parentNode;
  while (eventIterator.previousElementSibling != null) {
    eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.previousElementSibling;
  }
  eventIterator = event.target.parentNode;
  while (eventIterator.nextElementSibling != null) {
    eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
    eventIterator = eventIterator.nextElementSibling;
  }
  const fac = new FastAverageColor();
  fac.getColorAsync(event.target)
    .then((color) => this.$emit('theater-mode', color.rgba))
    .catch(function(e) {
      console.log(e);
    });
}

That should look good to you! Let’s look back at App.vue.

App.vue
<template>
  <div id="app">
    <PhotoGallery/>
  </div>
</template>

<script>
import PhotoGallery from './components/PhotoGallery.vue'

export default {
  name: 'App',
  components: {
    PhotoGallery
  },
  methods: {
    setBackground(rgba) {
      document.querySelector('body').style.backgroundColor = rgba;
    }
  }
}
</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>

We already discussed that listening to the theater-mode event looks like v-on:theater-mode. When we listen for a custom event, we can access any data that is passed with it via $event.

So, we write the following:

<template>
  <div id="app">
    <PhotoGallery v-on:theater-mode="setBackground($event)"/>
  </div>
</template>

Congratulations!

You just successfully emitted a custom event, listened to it from a parent component and accessed the value emitted from the event. Check your browser. Your app should be working just as we intended it to. Good job and bon voyage! 🚢

If you’re interested in furthering your knowledge around component communication in Vue, I recommend you give this article a read.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Parthiv Mohan

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more