I’ve previously here presented some custom event using jQuery and made this summer a lightning talk at the Webtuesday presenting most of the event mechanisms I know. I went through DOM0 and DOM2 events but missed DOM3 which offers what I called CustomEvent
(using the same name as YUI’s). The ultimate goal of using event is to come with small and reusable modules loosely coupled together. For that purpose I created a carousel module, which only does the carousel (reading isn’t usable alone).
But first, go back to DOM0 and how you can do DOM0 modules. This is DOM0.
document.body.onclick = function(event) { alert("clicked"); };
I compared it to the delegates that uses C# (using =+
and =-
though). It’s possible to create an object that will call functions you defined when something happened. You’ll have to override those method to get the callback but as only one callback is allowed per event, i.e. onclick
it can get tricky.
DOM2 introduced the event listeners (à la Swing), which is called event handlers in the MSIE world, but I guess you know the story. The event listeners enable (mainly) to have multiple listeners per event.
document.body .addEventListener("click", function(event) { alert("clicked"); }, false );
This works well for existing DOM events fired by the browser itself but in order to build more specific applications, the different libraries came up with their way of doing it. Inspired by Qt connect, by a channel-based publication/subscription like XMPP, by the Observer pattern from the GOF there are many solutions giving their abstraction of the existing model.
DOM3 introduces a custom event called Event (or Events), like MouseEvent (mousemove
), HTMLEvent (click
), MutationEvent (change
), …
to do what you want with it. My idea is to create a module that encapsulate a DOM Node and offers the same interface as the other nodes. Basically:
function Module(element) { this.element = element; }; Module.prototype.addEventListener = function(name, listener, capture) { return element.addEventListener(name, listener, capture); }; Module.prototype.removeEventListener = function(name, listener, capture) { return element.removeEventListener(name, listener, capture); };
The dispatchEvent
function is missing from the original interface, up to you to add it.
var bd = new Module(document.body); bd.addEventListener("click", function(event) { alert("clicked"); }, false );
From that point, I can consider this instance as a DOM Node, with special powers. Let’s add them.
Module.prototype.hide = function() { this.element.style.visibility = "hidden"; this.changed(); }; Module.prototype.show = function() { this.element.style.visibility = "show"; this.changed(); };
Not magic yet…
Module.prototype.changed = function() { var event = document.createEvent("Events"); event.initEvent("visible", true, true); event.visilibility = this.element.style.visibility; this.element.dispatchEvent(event); };
So, when anyone shows or hides this element, it will fire a visible
event. As you might have noticed, the event listener isn’t binding the module, so "this" isn’t the module but the DOM tag itself (this can be fixed of course, I just wanted to keep it simple).
bd.addEventListener("visible", function(event) { alert(event.visibility); }, false );
The goal of this, and this is overused inside YUI, is to create independent modules/component/widgets that aren’t explicitly linked to each other but communicate using events.
So the mentioned above carousel has a pagination and a status displaying the current page and the total number of pages. Those two elements aren’t linked to the carousel explicitly. They fire a page
event containing the information about the current page (and some other useful bits). If you’re crazy enough, it’s possible to pilot n carousel from one pagination, or one carousel with n paginations.
Simple modules, small code, infinite possibilities, just like LEGO’s.
I think that by having such a simple architecture can enable a better reutilization, simpler unit testing and more modularity. How small a graphical module can be in term of functionalities, can it be smaller? Do it. DOM3 applies to the content of the page, so to the UI of it and isn’t appropriate to be used with XMLHttpRequest or other asynchronous elements of course. This is why it will mostly be used on graphical widgets to put together a rich interface than on the part that communicates with a server for example.
As a conclusion, DOM3 isn’t still on all the browsers so you’d better stick to yours favourite libraries if you aim to cover a wide range of browsers.