Skip to content

Instantly share code, notes, and snippets.

@AnthonyGilliam
Created May 5, 2017 14:41
Show Gist options
  • Save AnthonyGilliam/b244318c801abae2012e559d895c3b64 to your computer and use it in GitHub Desktop.
Save AnthonyGilliam/b244318c801abae2012e559d895c3b64 to your computer and use it in GitHub Desktop.
Correcting bugs in aurelia-event-aggregator.js concerning pub/sub functionality.
import * as LogManager from 'aurelia-logging';
const logger = LogManager.getLogger('event-aggregator');
class Handler {
constructor(event, callback) {
this.event = event;
this.callback = callback;
}
handle(event, data) {
if (event === this.event) {
this.callback.call(null, data, event);
}
}
}
function invokeCallback(callback, data, event) {
try {
callback(data, event);
} catch (e) {
logger.error(e);
}
}
function invokeHandler(handler, event, data) {
try {
handler.handle(event, data);
} catch (e) {
logger.error(e);
}
}
/**
* Represents a disposable subsciption to an EventAggregator event.
*/
interface Subscription {
/**
* Disposes the subscription.
*/
dispose(): void;
}
/**
* Enables loosely coupled publish/subscribe messaging.
*/
export class EventAggregator {
/**
* Creates an instance of the EventAggregator class.
*/
constructor() {
this.eventLookup = {};
this.messageHandlers = [];
}
/**
* Publishes a message.
* @param event The event or channel to publish to.
* @param data The data to publish on the channel.
*/
publish(event: string | any, data?: any): void {
let subscribers;
let i;
if (!event) {
throw new Error('Event was invalid.');
}
if (typeof event === 'string') {
subscribers = this.eventLookup[event];
if (subscribers) {
subscribers = subscribers.slice();
i = subscribers.length;
while (i--) {
invokeCallback(subscribers[i], data, event);
}
}
} else {
subscribers = this.messageHandlers.slice();
i = subscribers.length;
while (i--) {
invokeHandler(subscribers[i], event, data);
}
}
}
/**
* Subscribes to a message channel or message type.
* @param event The event channel or event data type.
* @param callback The callback to be invoked when when the specified message is published.
*/
subscribe(event: string | Function, callback: Function): Subscription {
let handler;
let subscribers;
if (!event) {
throw new Error('Event channel/type was invalid.');
}
if (typeof event === 'string') {
handler = callback;
subscribers = this.eventLookup[event] || (this.eventLookup[event] = []);
} else {
handler = new Handler(event, callback);
subscribers = this.messageHandlers;
}
subscribers.push(handler);
return {
dispose() {
let idx = subscribers.indexOf(handler);
if (idx !== -1) {
subscribers.splice(idx, 1);
}
}
};
}
/**
* Subscribes to a message channel or message type, then disposes the subscription automatically after the first message is received.
* @param event The event channel or event data type.
* @param callback The callback to be invoked when when the specified message is published.
*/
subscribeOnce(event: string | Function, callback: Function): Subscription {
let sub = this.subscribe(event, (a, b) => {
sub.dispose();
return callback(a, b);
});
return sub;
}
}
/**
* Includes EA functionality into an object instance.
* @param obj The object to mix Event Aggregator functionality into.
*/
export function includeEventsIn(obj: Object): EventAggregator {
let ea = new EventAggregator();
obj.subscribeOnce = function(event, callback) {
return ea.subscribeOnce(event, callback);
};
obj.subscribe = function(event, callback) {
return ea.subscribe(event, callback);
};
obj.publish = function(event, data) {
ea.publish(event, data);
};
return ea;
}
/**
* Configures a global EA by merging functionality into the Aurelia instance.
* @param config The Aurelia Framework configuration object used to configure the plugin.
*/
export function configure(config: Object): void {
config.instance(EventAggregator, includeEventsIn(config.aurelia));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment