Creating a JavaScript Event Bus

With the help of the event bus, we are able to broadcast JavaScript event across different “platforms”. For example, we can trigger a Vue component’s method from a native JavaScript event. Let’s see how!

Getting Started

Recently, I bumped into a problem, when I had to trigger Vue components from native JavaScript. Sometimes we can’t wrap everything in a Vue instance, so we need to broadcast states and events across native JS and Vue (or another framework).  Basically, event bus is to solve this kind of problems in general.

The concept of an event bus is very simple. You have an event handler platform, what is globally reachable, triggerable from any kind of JavaScript. You can add and remove event listeners to the bus, also you can dispatch events with the help of the event bus and if any listener was registered to the event, the given callback will be triggered.

The Anatomy of the Event Bus

The code is very simple. We are basically creating a fake element and use it as a proxy for the events and listeners. Of course, sometimes, you need a bit more complex code to achieve what you want, but for now, we keep it very simple.

export default class EventBus
{
    /**
     * Initialize a new event bus instance.
     */
    constructor()
    {
        this.bus = document.createElement('fakeelement');
    }

    /**
     * Add an event listener.
     */
    addEventListener(event, callback)
    {
        this.bus.addEventListener(event, callback);
    }

    /**
     * Remove an event listener.
     */
    removeEventListener(event, callback)
    {
        this.bus.removeEventListener(event, callback);
    }

    /**
     * Dispatch an event.
     */
    dispatchEvent(event, detail = {})
    {
        this.bus.dispatchEvent(new CustomEvent(event, { detail }));
    }
}
Notice, we even keep the function names to keep it as simple as possible.

Using the Event Bus

All we need to do is to assign a bus instance to the window object and from that point, it’s globally reachable.

import EventBus from './EventBus';
window.EventBus = new EventBus;
Of course, if we wish we can initialize multiple buses as well.

Dispatching events on the bus is very easy as well. Basically, we can dispatch any event anytime, it really depends on the need of the application.

document.querySelector('#native-button').addEventListener('click', event => {
    window.EventBus.dispatchEvent('open-vue-modal', { id: 'specific-modal' });
});

As we see, we can trigger a bus event when the button was clicked. Also, we can pass data for the listener if we wish, because behind the scenes the bus fires a CustomEvent instance.

Now, we can listen to the event from anywhere. Let’s say we want to open a Vue modal when a native button was clicked. This is the modal component’s code:

<script>
...
    created() {
        window.EventBus.addEventListener('open-vue-modal', event => {
            if (event.detail.id === this.id) {
                this.open();
            }
        });
    }
...
</script>

<template>
...
</template>

If the modal accepts an ID property, we can even filter down to specific modal. It’s useful especially if we have multiple modal components at the same time. But of course, we can pass to the event any data we wish.

Summary

The event bus concept can be a nice bridge between your native JS and Vue “platforms”. It’s nice to have these little solutions when we want to keep the code small and the application maintainable.

Special thanks for the following recource(s): Icon made by Smashicons from www.flaticon.com