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
andnewsletter
. - The components don’t know each other exist.
- The components exist on the same 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.
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:
- We import the event bus from our file.
- We register the event handler when the component is mounted.
- We have a method
hello
that will handle our event. - When we invoke
signUp
, it emits thehello
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.
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.
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. :)