Created
October 19, 2011 21:48
javascript observer pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var MyNs = { | |
events: { | |
Manager: {} | |
} | |
}; | |
/** | |
* This creates a new Publisher/Subscriber object | |
* @example: | |
var eventManager = new MyNs.events.Manager, | |
events = { | |
something: { | |
awesome: function () { | |
console.log('this event does something awesome'); | |
} | |
} | |
}; | |
eventManager.addPublisher('event:name'); // 'event:name' is an arbitrary value | |
eventManager.subscribe('event:name', events, 'something.awesome'); | |
... some super coding stuff ... | |
eventManager.publish('event:name'); | |
// in the console: | |
// this event does something awesome | |
// to unsubscribe: | |
eventManager.unsubscribe('event:name', 'something.awesome'); | |
* | |
* NOTE: if "event:name" is not firing, make sure "event:name" was added via addPublisher | |
* @return MyNs.events.Manager mapped to PubSubManager. Notice it does not create a "new" instance. This must be declared in your own script | |
*/ | |
(function (window, MyNs) { | |
var SLICE = Array.prototype.slice; | |
function PubSubManager() {} | |
/** | |
* Adds an event to publish/fire | |
* @param arguments {Mixed} 1..n number of events to add | |
*/ | |
PubSubManager.prototype.addPublisher = function () { | |
var events = arguments; | |
if (!this.publishers) { | |
this.publishers = {}; | |
} | |
for (var i = 0, len = events.length; i < len; i++) { | |
if (!this.publishers[events[i]]) { | |
this.publishers[events[i]] = []; | |
} | |
console.log("created this.publishers[" + events[i] + "] with ", this.publishers[events[i]].length, ' publishers') | |
} | |
}; | |
/** | |
* Fires off an event. If it does not fire, make sure it has been added via addPublisher | |
* @param event {String} The name of the event to fire. | |
*/ | |
PubSubManager.prototype.publish = function (event) { | |
var args = SLICE.call(arguments, 1); | |
if (this.publishers[event]) { | |
console.log('publishing ', event) | |
for (var i = 0, len = this.publishers[event].length; i < len; i++) { | |
this.publishers[event][i].fn.apply(this, args); | |
} | |
} | |
}; | |
/** | |
* Adds a subscriber to the publisher | |
* @param event {String} Event name | |
* @param scope {object} The scope of the @handlerName | |
* @param handlerName {String} Period delimited string of the namespace to target within the @scope | |
*/ | |
PubSubManager.prototype.subscribe = function (event, scope, handlerName) { | |
var curryArr = SLICE .call(arguments, 3); | |
if (this.publishers[event]) { | |
// using an internal object allows for unusbscribing objects from events | |
this.publishers[event].push({ | |
ns: handlerName, | |
fn: function () { | |
var normalArgs = SLICE.call(arguments, 0), | |
nested = handlerName.split('.'); | |
scope = (nested.length > 1) ? getNestedObj(scope, nested) : scope[handlerName]; | |
scope.apply((scope || window), curryArr.concat(normalArgs)); | |
} | |
}); | |
} | |
}; | |
/** | |
* Removes a subscriber from a publisher | |
* @param event {String} The event/publisher name | |
* @param handlerName {String} Period delimited string of the namespace to target | |
*/ | |
PubSubManager.prototype.unsubscribe = function (event, handlerName) { | |
if (this.publishers[event]) { | |
for (var i = this.publishers[event].length; i--;) { | |
if (this.publishers[event][i]) { | |
if (this.publishers[event][i].ns === handlerName) { | |
this.publishers[event].splice(i, 1); | |
return; | |
} | |
} | |
} | |
} | |
}; | |
/** | |
* Recursively finds the "names" (object) within the scope | |
* @param scope {object} The scope to start from | |
* @param names {array} The "names" (object) to find within the scope | |
*/ | |
function getNestedObj(scope, names) { | |
if (typeof names === 'string') { | |
return scope[names]; | |
} | |
var len = names.length; | |
while (len--) { | |
var ns = names.shift(); | |
if (scope[ns]) { | |
scope = scope[ns]; | |
} | |
} | |
return scope; | |
} | |
MyNs.events.Manager = PubSubManager; | |
}(window, MyNs)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment