Yoan Blanc’s weblog

Another lost swiss guy

Introduction to jQuery’s custom event

Yoan BlancWed, 30 Apr 2008, , ,

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.logs 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.

Étant sur un projet qui peut s’apparenter à une application riche avec énormément d’appel XHR (dit Ajax), je suis tombé nez à nez avec deux des plus belles fonctionnalités de jQuery (au delà de extend), j’ai nommé bind et trigger. Elle permettent de faire ce qu’on peut appelé Pub/Sub ou le design pattern du Gang of Four : Observer, un principe bien connu et plutôt évident. YUI offre le CustomEvent et Dojo un mécanisme similaire à jQuery, au cas où vous les connaitriez déjà c’est à ce moment-là qu’il faut hocher de la tête en approbation.

Pour ne pas changer des bonnes habitudes, les exemples sont dans la partie anglophone, ils doivent fonctionner via la console firebug pour autant que vous soyez sur un site qui utilise jQuery.

Tout ceci pour arriver au clou du spectacle, cherchant un outil qui puisse faire un usage fondé de cette gymnastique évènementielle. Un jeu pardis! Donc, vous pouvez trouver ici un Sudoku reposant essentiellement sur une communication évènementielle : pas de module pattern, ni de classes/objets (et il est bien évidemment possible d’avoir plusieurs sudoku dans la même page, sinon ça n’est pas drôle).

Les avantages de cette approche là, au delà du fait qu’il y a un découplage fort entre les différents éléments sont : plus de debug dans le code du cœur puisqu’il suffit d’écouter les évènements (voir le logger), ajout de fonctionnalité par écoute d’évènements existant (par exemple: sauvegarde de la partie sur le serveur en direct, coloration des cellules jouées en fonction du temps permettant de visuellement avoir une mémoire des coups récents face au autres, etc.). Et avec ça, faire du refactoring est très simple étant donné le couplage très faible de tout.

Amusez-vous bien!

About

meYoan Blanc is a web developer that lives in Lausanne (rue Couchirard 15, 1004 Switzerland) worked for Yahoo! and comes from La Chaux-de-Fonds. This web site is for this weblog, a playground for random stuffs and can help keepingmeconnected with some friends out there.

Get my vCard or contact me by phone (+41 21 625 82 09) or email ().

Misc

RSS, list.blogug.ch

This site reflects only my opinion and is not affiliated with anyone else.

copyright 2006-2008 — doSimple.ch