Create a gist now

Instantly share code, notes, and snippets.

A simple, tiny and robust JavaScript observer
/**
* observer
*
* A namespace for observers. To create one, simply call the `makeObserver`
* function:
*
* var observer = makeObserver();
*
* This allows multiple observers to be run if needed. Subscribe to events
* using [[observer.on]], unsubscribe using [[observer.off]] and trigger events
* with [[observer.trigger]].
**/
function makeObserver() {
var dummy = document.createElement("div");
var handlers = new WeakMap();
// Internal function that modifies the given handler and returns that
// modification.
function modify(handler) {
var modified = handlers.get(handler);
if (!modified) {
modified = function (e) {
handler(e.detail);
};
handlers.set(handler, modified);
}
return modified;
}
// Internal function that gets the modified version of the handler if it
// exists, or the original if there is no modification.
function getModified(handler) {
return handlers.get(handler) || hander;
}
/**
* observer.on(name, handler)
* - name (String): Name of the event.
* - handler (Function): Event handler to execute.
*
* Subscribes an event to the observer.
*
* observer.on("event", function (data) {
* console.log(data);
* });
* observer.trigger("event", {
* triggered: true
* });
* // Logs: { triggered: true }
*
**/
function on(name, handler) {
dummy.addEventListener(name, modify(handler));
}
/**
* observer.off(name, handler)
* - name (String): Name of the event.
* - handler (Function): Event handler to remove.
*
* Removes an event handler from the named event.
*
* var handler1 = function () {
* console.log(1);
* };
* var handler2 = function () {
* console.log(2);
* };
* observer.on("event", handler1);
* observer.on("event", handler2);
* observer.trigger("event");
* // Logs: 1
* // Logs: 2
* observer.off("event", handler1);
* observer.trigger("event");
* // Logs: 2
*
* Be warned that the function has to be passed by reference.
*
* observer.on("event2", function () {
* console.log(1);
* });
* observer.off("event2", function () {
* console.log(1);
* });
* observer.trigger("event2");
* // Logs: 1 - event was not unsubscribed.
*
**/
function off(name, handler) {
dummy.removeEventListener(name, getModified(handler));
}
/**
* observer.trigger(name[, detail])
* - name (String): Name of the event to trigger.
* - detail (?): Optional information to pass to the event.
*
* Triggers the named event.
*
* observer.on("event1", function () {
* console.log(1);
* });
* observer.trigger("event1");
* // Logs: 1
*
* Optionally, information can be passsed to the event using the `detail`
* argument and it will be available in the `detail` property of the event
* argument.
*
* observer.on("event2", function (e) {
* console.log(e.detail);
* });
* observer.trigger("event2", "information");
* // Logs: "information"
*
**/
function trigger(name, detail) {
dummy.dispatchEvent(new CustomEvent(name, {
bubbles: true,
cancelable: true,
detail: detail
}));
}
return Object.freeze({
on: on,
off: off,
trigger: trigger
});
}
function makeObserver(){function e(b){var a=c.get(b);a||(a=function(a){b(a.detail)},c.set(b,a));return a}var d=document.createElement("div"),c=new WeakMap;return Object.freeze({on:function(b,a){d.addEventListener(b,e(a))},off:function(b,a){d.removeEventListener(b,c.get(a)||hander)},trigger:function(b,a){d.dispatchEvent(new CustomEvent(b,{bubbles:!0,cancelable:!0,detail:a}))}})};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment