Building an Ember Message Bus

Building an Ember Message Bus

Mar 29, 2016
Javascript, Ember

When I was looking for an event bus for the Ember application I was writing for work I came across Paul Cowan’s blog article called Emberjs - Simple Global Event Bus. This event bus uses the built in Ember.Evented and at it’s core looks as follows:

App.EventBus = Ember.Service.extend(Ember.Evented, {
  publish: function() {
    return this.trigger.apply(this, arguments);
  },
  subscribe: function() {
    return this.on.apply(this, arguments);
  },
  unsubscribe: function() {
    return this.off.apply(this, arguments);
  }
});

I’m using ember-cli 2.4.2 so my actual event bus file and it’s associated initializer looked as follows:

import EventBus from '../vxs-eventbus/service';

export function initialize(application) {
    let eventBus = new EventBus();

    application.register('service:vxs-eventbus', eventBus, {
        instantiate: true,
        singleton: true
    });

    application.inject('route', 'eventbus', 'service:vxs-eventbus');
    application.inject('component', 'eventbus', 'service:vxs-eventbus');
    application.inject('controller', 'eventbus', 'service:vxs-eventbus');
}

export default {
    name: 'vxs-eventbus',
    after: 'vxs-logger',
    initialize
};

If you are using ember-cli then your service has to have a hyphen in it. Notice that I’m defining it as a singleton and in the export default I’m saying it needs to be initialized after the vxs-logger service.

import Ember from 'ember';

export default Ember.Service.extend(Ember.Evented, {
    name: 'vxs-eventbus',

    /*
     * Publishes an event to the event bus
     */

    publish: function() {
        return this.trigger.apply(this, arguments);
    },

    /*
     * Subscribe to an event from the event bus
     */

    subscribe: function() {
        return this.on.apply(this, arguments);
    },

    /*
     * Unsubscribe to an event from the event bus
     */

    unsubscribe: function() {
        return this.off.apply(this, arguments);
    }
});

As you can see this is identical to the one in the blog article, just with some documentation.

The interesting part comes when you want to use this. As you can see from the initializer I’m injecting this into routes, controllers and components, so using the event bus in any of those is relatively simple.

this.get('eventbus').publish('_eventName', data);

where the _eventName is the name you want to use to uniquely identify that event. I tend to use _event as the first part of the name so that I know it is actually an event I’m at looking at but you can use whatever name standard works for you.The data parameter is optional. You can also inject a service into a model as well.

If you want to catch this event in a module then you need to switch it on.

this.get('eventbus').on('_eventName', this, 'functionToCall');

When the _eventName is called this will cause the functionToCall to be run with the associated data you passed in the event.

One thing you did need to remember to do though is when you leave that route for example is to switch the event off, otherwise next time you go into that route the event will get called twice. So:

this.get('eventbus').off('_eventName', this, 'functionToCall');

Where exactly you switch the events on and off will depend on how you are using and whether they are page wide or just component wide.

The interesting part comes when you want to use the event bus in another service. We will look at that in the next entry Using Service in Services in Ember.