Reputation: 499
I'm creating a client-side dynamic blog engine. Now I need a event system to handle many actions from DOM elements and the engine. Such as the engine is loading a article,user is switching a theme...
And I don't want to use a library to do this.
So far I've done is using a list to store callbacks for a event.
But I want each callback works with different objects.Like the DOM event.
I may add an id-like property to each object, and store (id,callbacks) in a event.I feel it's not so good.When comes with dynamically generated object,it could be complex to deal with.
How to implement it as simple as DOM event (to use)?
Upvotes: 1
Views: 2928
Reputation: 147
ok was recently looking into this settled on this https://github.com/browserify/events#readme just so its consistent in my personal enviroment but I also want to paste in a basic one I found in the slick grid project this is pretty useful for only being 150 lines of code and I think gives a good basic understanding of events
/***
* An event object for passing data to event handlers and letting them control propagation.
* <p>This is pretty much identical to how W3C and jQuery implement events.</p>
* @class EventData
* @constructor
*/
function EventData() {
var isPropagationStopped = false;
var isImmediatePropagationStopped = false;
/***
* Stops event from propagating up the DOM tree.
* @method stopPropagation
*/
this.stopPropagation = function() {
isPropagationStopped = true;
};
/***
* Returns whether stopPropagation was called on this event object.
* @method isPropagationStopped
* @return {Boolean}
*/
this.isPropagationStopped = function() {
return isPropagationStopped;
};
/***
* Prevents the rest of the handlers from being executed.
* @method stopImmediatePropagation
*/
this.stopImmediatePropagation = function() {
isImmediatePropagationStopped = true;
};
/***
* Returns whether stopImmediatePropagation was called on this event object.\
* @method isImmediatePropagationStopped
* @return {Boolean}
*/
this.isImmediatePropagationStopped = function() {
return isImmediatePropagationStopped;
};
}
/***
* A simple publisher-subscriber implementation.
* @class Event
* @constructor
*/
function Event() {
var handlers = [];
/***
* Adds an event handler to be called when the event is fired.
* <p>Event handler will receive two arguments - an <code>EventData</code> and the <code>data</code>
* object the event was fired with.<p>
* @method subscribe
* @param fn {Function} Event handler.
*/
this.subscribe = function(fn) {
handlers.push(fn);
};
/***
* Removes an event handler added with <code>subscribe(fn)</code>.
* @method unsubscribe
* @param fn {Function} Event handler to be removed.
*/
this.unsubscribe = function(fn) {
for (var i = handlers.length - 1; i >= 0; i--) {
if (handlers[i] === fn) {
handlers.splice(i, 1);
}
}
};
/***
* Fires an event notifying all subscribers.
* @method notify
* @param args {Object} Additional data object to be passed to all handlers.
* @param e {EventData}
* Optional.
* An <code>EventData</code> object to be passed to all handlers.
* For DOM events, an existing W3C/jQuery event object can be passed in.
* @param scope {Object}
* Optional.
* The scope ("this") within which the handler will be executed.
* If not specified, the scope will be set to the <code>Event</code> instance.
*/
this.notify = function(args, e, scope) {
e = e || new EventData();
scope = scope || this;
var returnValue;
for (var i = 0; i < handlers.length && !(e.isPropagationStopped() || e.isImmediatePropagationStopped()); i++) {
returnValue = handlers[i].call(scope, e, args);
}
return returnValue;
};
}
function EventHandler() {
var handlers = [];
this.subscribe = function(event, handler) {
handlers.push({
event: event,
handler: handler
});
event.subscribe(handler);
return this; // allow chaining
};
this.unsubscribe = function(event, handler) {
var i = handlers.length;
while (i--) {
if (handlers[i].event === event &&
handlers[i].handler === handler) {
handlers.splice(i, 1);
event.unsubscribe(handler);
return;
}
}
return this; // allow chaining
};
this.unsubscribeAll = function() {
var i = handlers.length;
while (i--) {
handlers[i].event.unsubscribe(handlers[i].handler);
}
handlers = [];
return this; // allow chaining
};
}
console.log("Start Demo")
car1 = {}
car1.onhonk = new Event();
car1.honk = ()=>{
console.log('car1 Honked');
car1.onhonk.notify({noise:'meep meep'})
};
car2 = {}
car2.honkListener = (e, args) => {
console.log("car2 heard: ", args.noise);
}
car1.honk();//not heard yet
car1.onhonk.subscribe(car2.honkListener);
car1.honk();
Upvotes: 0
Reputation: 1
class SimpleEvent {
constructor() {
this.onEvent = {}
this.handler = function(funct, name) {
var owner = this
var name = name
this.onEvent[name] = funct
var remove = function() {
delete this.owner.onEvent[this.name]
delete this.owner
delete this.name
delete this.remove
}
if ((((!(remove == undefined && name == undefined)) && (remove == undefined || name == undefined)))) {
throw new Error("-_-")
} else {
return (remove == undefined || name == undefined) ? (undefined) : ({
remove: remove,
name: name
})
}
}
}
Fire() {
for (var i in this.onEvent) {
this.onEvent[i](arguments)
}
}
}
Upvotes: 0
Reputation: 135187
Recently, I wanted to add simple event listeners to vanilla JavaScript objects. This is the solution I came up with
(This requires ecmascript >= 5
)
function Emitter () {
var eventTarget = document.createDocumentFragment();
function delegate (method) {
this[method] = eventTarget[method].bind(eventTarget);
}
Emitter.methods.forEach(delegate, this);
}
Emitter.methods = ["addEventListener", "dispatchEvent", "removeEventListener"];
Now a "class" that uses it
function Example () {
Emitter.call(this);
}
Let's try it out now!
var e = new Example();
e.addEventListener("something", function(event) {
alert("something happened! check the console too!");
console.log(event);
});
e.dispatchEvent(new Event("something"));
Good luck!
Upvotes: 2
Reputation: 3491
You could implement mediator pattern:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#mediatorpatternjavascript
In this book is everything you need to know about it.
Upvotes: 0