Reader, ahazelwood, recently read my post on using ASP.NET Core, VueJS, and Parcel to build a robust application architecture. He did have one follow up question that I thought I would address in this post. He wanted to know how to communicate between Vue components and trigger methods between different parts of functionality on the page. In this post, I’ll show you how to take my JAMStack project and add an event bus between components.

What’s an Event Bus

User actions and events are the building blocks of all user interfaces. The user clicks a button, and a function handles the work. An event bus is a mechanism to manage events and their handlers. In addition to frequent activities like clicks, drags, and form submissions, an event bus allows programmers to define custom events with specific arguments. We’ll be establishing a custom event of hello later in this post.

The Structure Of Our Page

Before we get into the code, let’s get familiar with the structure of our project.

  • We have two Vue Components: contact and newsletter.
  • The components don’t know each other exist.
  • The components exist on the same page.

vue components on page

Our goal is to allow the components to talk to each other and trigger each other’s functionality.

Adding EventEmitter For The Event Bus

Our first step is to install the EventEmitter package via NPM.

npm install EventEmitter

Once installed, you should see the package in your package.json file.

"dependencies": {
  "EventEmitter": "^1.0.0"
}

The next step is to add an eventbus.js file to your project. This file will contain our single instance of the EventEmitter object. Be sure to use const to declare your event bus.

import EventEmitter from "EventEmitter";
export const bus = new EventEmitter();

When completed, your directory should look like the following.

event bus directory

Using Our Event Bus

We’re halfway to our goal, but we need to use our event bus now. Let’s look at one of our components.

import axios from 'axios';
import { bus } from '../eventbus';

export default {
    mounted() {
      bus.on('hello', this.hello);  
    },
    data() {
        return {
            email : '',
        }
    },
    methods : {
        signUp(event) {
            event.preventDefault();
            let data = {
                email: this.email,
            };
            
            bus.emit('hello', this.email);

            axios
                .post(`/newsletter`, data)
                .then(response => {
                    alert(`Thank You!`);
                });
        },
        hello(name) {
            console.log(`hello from newsletter ${name}`);
        }
    }
}

There are four essential points to take note of in the code:

  1. We import the event bus from our file.
  2. We register the event handler when the component is mounted.
  3. We have a method hello that will handle our event.
  4. When we invoke signUp, it emits the hello event with a single argument.

This component can handle its emitted event, but we also do the same in our contact component.

import axios from 'axios';
import { bus } from '../eventbus';

export default {
    mounted() {
        bus.on('hello', this.hello)
    },
    data() {
        return {
            name : '',
            email : '',
            message : '',
        }
    },
    methods : {
        sendMessage(event) {
            event.preventDefault();
            let data = { 
                name: this.name, 
                email: this.email, 
                message: this.message
            };
            
            // let's let all the other components know
            bus.emit('hello', this.name);

            axios
                .post(`/contact`, data)
                .then(response => {
                    alert(`Thank You ${response.data.name}!`);
                });
        },
        hello(name) {
            console.log(`hello, from contact form ${name}!`);
        }
    }
}

As you can see, the code is almost identical.

Riding The Event Bus

Let’s take our event bus for a spin. There should be no surprises on what to expect. When we go to our page and activate our newsletter component, we see both components trigger their hello functions.

event bus working

Woot! It works!

Let Others Ride The Bus

There is one other technique you can take advantage of in your application. I don’t recommend it, but its an acceptable way to expose your event bus to other libraries.

Within your JavaScript files, you can add the event bus to your window object and make it available at the global level.

import Vue from 'vue';
import vueCustomElement from 'vue-custom-element'
import helloWorld from './components/helloworld'
import contactForm from './components/contact'
import newsletter from "./components/newsletter";

// import the event bus
import { bus } from "./eventbus";

Vue.use(vueCustomElement);

Vue.customElement('hello-world', helloWorld);
Vue.customElement('news-letter', newsletter);
Vue.customElement('contact-form', contactForm);

// add the event bus to window
window.bus = bus;

In the browsers console, we can now trigger our event.

event bus working in consle window

window.bus.emit('hello', 'cool beans');
hello from newsletter cool beans
hello, from contact form cool beans!

Cool beans indeed for the folks who may need to extend your application without being able to affect your build process.

Conclusion

An event bus is a great way to share information and actions across many components that don’t need to know each other exist. In this post, I showed how, with just a few lines, you could increase the capabilities of your application. You could also expose the event bus via the window object for others to extend your app. I hope you found this post helpful, and I hope I answered your question ahazelwood. Feel free to ask more questions. :)