Quality Reads

Tuesday, May 22, 2007

Prototype Custom Event System

Perhaps I have a little Flex envy but the DOM event model is woefully ill-suited to handle dynamic single page applications. To remedy the situation, I've written an extension for Prototype to provide a Custom Event messaging system. Its designed to work as a mediator between your AJAX controller and services. The concept works something like this:
  1. A user clicks a button (or interacts with any UI component) and a DOM event is triggered. Typically captured using Event.observe.
  2. The controller receives the DOM event, checks the state of the application, and gathers any data required by the model.
  3. Then using the Custom Event framework, a Custom Event is broadcasted with all the data the Model needs to perform its actions.
  4. The Model receives the Custom Event, processes its service call (or data storage etc.), and then uses its own Custom Event to broadcast data back to the controller.
  5. The controller then updates the view accordingly.

Custom Events are not a replacement for the Event object. Its really meant to aid in the loose coupling of the Model from the Controller in your client side code. Now that you've heard my spiel. Here's the code:



CustomEvent = {};
CustomEvent.Events = {};
CustomEvent.Events.Base = Class.create();
CustomEvent.Events.Base.prototype = {
initialize: function(){
this.listeners = new Array();
},
addEventListener: function(f){
this.listeners.push(f);
},
removeEventListener: function(f){
this.listeners = this.listeners.without(f);
},
dispatchEvent: function(n, d){
var data = this.setupData(d);
this.listeners.each(function(l){
l({name : n}, data);
});
},
setupData: function(d){
return $H(d);
}
}
CustomEvent.EventController = Class.create();
CustomEvent.EventController.prototype = {
initialize: function(){
this.events = new Hash();
},
create: function(n, t){
var args = arguments[2]?arguments[2]:null;
this.events[n] = new Event.CustomEvent[t](args);
},
addEventListener: function(n, f){
this.events[n].addEventListener(f);
},
removeEventListener: function(n, f){
this.events[n].removeEventListener(f);
},
dispatchEvent: function(){
var n = arguments[0];
var d = arguments[1] ? arguments[1] : {};
this.events[n].dispatchEvent(n, d);
},
destroy: function(n){
this.events.remove(n);
}
}
var EventController = new CustomEvent.EventController();


Here's how you would use it.


EventController.create("test", "Base");
EventController.addEventListener("test", myTest);

function myTest(evt){
alert('Event Name: '+evt.name);
}


Base is just the Basic custom event. Extend it to specify a unique data structure. Trigger the event with the following code:


EventController.dispatchEvent("test");


I still need to tweak the code little bit but so far its been very useful. Hope this helps someone else out.

Cheers,
Todd

No comments: