Working With The Aurelia Event Aggregator

The Event Aggregator is one of my favourite things about Aurelia and it is not even anything unique to Aurelia.

There does not seem to be much info out there about it, probably due to its simplicity. But I have noticed people ask about it in the Gitter chat from time-to-time. At its core the Event Aggregator is a pub/sub layer for publishing and listening to actions that take place inside of your application loosely.

If you look at the source of this module for Aurelia, you will see it is actually super simple to understand and how it works.

When to use the Event Aggregator

Like choosing to use anything, the decision to use the Event Aggregator module should be dictated by your application requirements. If your application requires knowing about what other parts are doing at various times in your application, the Event Aggregator can be incredibly helpful.

It allows you to fire off events that don’t have a specific target, events potentially multiple listeners could be looking out for. They are not essential, they are like observers, when something happens the subscriber methods are notified and allow you to act accordingly.

Everything comes with a cost, so don’t abuse it and use it for every change in your application, it is very much for those situations where cross component communication is essential.

Using the Event Aggregator

The Event Aggregator only has three exposed methods and they are incredibly easy to understand. Like any other Aurelia module, you import and inject it into your view model before using it.

import { inject } from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';

@inject(EventAggregator)
export class MyClass {
    constructor(EventAggregator) {
        this.ea = EventAggregator;
    }
}

All of the below descriptions of the Event Aggregator methods will use the above theoretical example of the Event Aggregator being injected and aliased on the class through injection as ea.

publish(event, data?)
The publish method allows you to fire off events. These events don’t have a specific target, they are loose events fired off into space. They don’t care who subscribes to them, there are no constraints on them.

The first argument is the name of the event, you can choose whatever name you want. For the below example, I chose “puppyMonkeyBaby” for no reason at all.

The second argument is data you want to supply along with your event and it is completely optional. Most of the time it will be an array or object of data. You can even just pass through a string value if you like as well. However, not all events need to supply data.

this.ea.publish('puppyMonkeyBaby', {testValue: 'What just happened?'});

subscribe(event, callbackFunction)

This is the method we use to listen to our published event. Taking the above creepy example of “puppyMonkeyBaby” lets get the value that was sent back, which was an object with one value.

The first parameter is the name of the event we are listening out for. The second argument is a function and in the below instance, we are using an arrow function to retain our view model scope for this context.

The callback function returns the supplied value as a parameter. In our case, it is an object, but if it was a string, it would be a string.

let subscription = this.ea.subscribe('puppyMonkeyBaby', response => {
    console.log(response);
    // This should yield: Object {testValue: "What just happened?"}
});

The above is the same as:

let subscription = this.ea.subscribe('puppyMonkeyBaby', function(response) {
    console.log(response);
    // This should yield: Object {testValue: "What just happened?"}
});

Worth pointing out is the subscribe method returns a function called dispose. This allows you to clean up and remove the subscriber once you are done with it. This might be in most cases inside of the detached lifecycle method of your view model.

Subscribe in action with dispose
Below is an example of a subscription that is removed when the view model is detached. This is a garbage collection measure and ensures your app does not use resources it no longer requires.

import { inject } from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';

@inject(EventAggregator)
export class MyClass {
    constructor(EventAggregator) {
        this.ea = EventAggregator;
    }

    attached() {
        this.subscriber = this.ea.subscribe('puppyMonkeyBaby', response => {
            console.log(response.testValue);
        });
    }

    detached() {
        this.subscriber.dispose();
    }
}

subscribeOnce(event, callbackFunction)
We won’t be giving any examples of this one in action. It is exactly the same as the above method, except this is a one time subscription. Once the event fires, the subscription is disposed of and never fired again.

This might be handy for situations where you only need to know if something happened once, like a page load.

Aurelia dependencies that use Event Aggregator

Various Aurelia dependencies actually use the Event Aggregator to communicate events taking place you can subscribe too within your app.

Because Aurelia is decoupled and can be built up with numerous dependencies, it makes Event Aggregator the ideal candidate.

Aurelia i18n
The translation dependency for Aurelia which allows you to support multiple languages in your application uses the Event Aggregator to communicate when the locale has changed here.

Aurelia Router
The router dependency is a great example of the Event Aggregator in use. You can see events being fired through the aggregator here. It allows you to listen for successful and unsuccessful route changes when the router is used.

If you want to see how the Event Aggregator works with the Router, I have written a convenient post here which describes how to do it.

If you are a plugin author, consider whether it would benefit you or make sense to use the Event Aggregator as well.