Trying doing a kind of RIA with a lot XHR (so called Ajax) messaging (very similar to Bayeux), I recently dived into what makes me enjoying working with jQuery. It’s two methods: bind (to bind an event like click
, mouseover
…) and trigger (to fire that event). They aims to solve the problem identical to the one of the GoF’s pattern called: Observer pattern. YUI has got a more pure implementation called CustomEvent that powers the AjaxEvent blogged by (awesome) Tim a time ago and Dojo’s one is very similar to jQuery’s.
Let’s begin, I bet you’ve already met .click()
or .blur()
, they are only shorcuts to .bind("click", …)
and .bind("blur", …)
. First example with a custom event called hello":
$({msg:"Hello World!"}). bind("hello", function(){ alert(this.msg); }). trigger("hello");
That will show you an alert saying “Hello World!”. $(...)
creates a jQuery object with {msg:…}
, bind binds to the event called “hello”
and will call alert using the key “msg”
from the origin object.
$({msg:"Hello"}). bind("hello", function(event, name){ alert(this.msg+" "+name); }). trigger("hello", ["World!"]);
More tricky now, the trigger will pass arguments to the binded function. The result is still the same: “Hello World!”. So you can pass arguments when an event is triggered.
$({msg:"Hello"}). bind("hello", "World!", function(event){ alert(this.msg+" "+event.data); }). trigger("hello");
Or when a function is binded, which is less useful but still. The result is always the same: “Hello World!”
What does this permits you? Tons of brilliant things. Like the AjaxEvent, you can dispatch Ajax results to different modules. You can decouple easily actions that have local actions. Imagine a world where all your console.log
s are outside your main module and inside a logger module and that it doesn’t break when you fires a browser without Firebug installed? Piece of cake:
$("*").bind("hello", function(event) { console.log( event.type+": "+ Array.prototype.slice.call(arguments, 1).join(", ")); });
This binding will be fired on any “hello”
event and log “hello: arg1, arg2, arg3, ...”. event.type contains the name of the event for the lazy. Tom built a JS script that does that for YUI Custom Event. It can run directly inside Firebug as well via a proper the extension.
There is a list of all binded events inside jQuery.event.global
, let’s use that to build a primitive logger.
for(var eventName in $.event.global) { $("*").bind(eventName, function(event) { console.log( event.type+": "+ event.target.nodeName+") "+ Array.prototype.slice.call(arguments, 1).join(", ")); }); }
Okay, now I’ve made a little Sudoku, which is a complete rip-off of the famous GNOME Sudoku (which rocks thus) that almost create a module with only bind/trigger and two jQuery.prototype
(aka jQuery.fn
) hacks, the logger and a show-me-the source for you lazy. No module pattern (of any kind), no OOP (except jQuery’s extra methods like conflicts
and replaceClass
). Only binding events on the sudoku table(s) — yes, you can have multiple tables in the same page — and triggering events within those bindings.
If all the information go through an event (or different events) it’s very easy to had a listener that can:
- keep track of the moves (using XHR i.e.),
- offer an undo/redo interface
- or even color the cells over the time so you can visually keep track of what is recent and what isn’t.
And all that without even modifying the existing code.