Firing Custom Events With The Prototype Javascript Framework
Tagged events, Javascript, Prototype
Yesterday Sam Stephenson released the final version of the Prototype Javascript Framework. I’ve been using RC0 and RC1 for some time and what I was missing in earlier releases of Prototype’s the ability to fire custom events. I’m going to use it to fire events in Plotr. In this post I’ll explain how to fire custom events, and of course how to observe those events.
Observing events
Let’s start by looking at how we can observe events. Imagine we have a form with a button and we want to be noticed when someone clicks it. The id of the button will be ‘button’. The event we’ll be observing is the click event. In the old days, assigned observer function to DOM elements with the ‘onclick’ attribute:
<input type="button" onclick="javascript:buttonClick(event);" id="button" value="Ok"/>
<script type="text/javascript">
function buttonClick(event){
alert(event);
}
</script>
This shows a very important point: the DOM element you want to observe events from, must exist in the DOM.
With Prototype, we can do things more unobtrusive:
<input type="button" id="button" value="Ok"/>
<script type="text/javascript">
// One way to observe the click event on the button
Element.observe('button', 'click', buttonClick);
// Another way, but has the same result
$('button').observe('click', buttonClick);
function buttonClick(event){
alert(event);
}
</script>
If you’re confused by all this, you’d better read more about the Event Class in the Prototype API. If you’re more like, ‘hey, let’s fire some events’, just read on.
Firing custom events
Most of the other well known Javascript Frameworks already had the functionality to fire custom events, and it took way too long (imo) before it appeared in Prototype. Anyway, firing events with Prototype is a bit different than other Frameworks. To fire an event, you must (!) add a namespace to the event name, otherwise it won’t fire. A custom event then would look like this: 'namespace:eventname'. This is what Sam has to say about it:
A small but important change was made to custom events in [7835]: all custom event names must now include a namespace. This is our solution to the problem of custom event names conflicting with non-standard native DOM events, such as “mousewheel” and “DOMMouseScroll.”
In the next example I’ll show how to fire the event ‘bar’ in the ‘foo’ namespace (so the event name will be ‘foo:bar’). Passed argument can be accessed by event.memo.
// Function that fires the 'bar' event in the 'foo'
// namespace. Note the second argument of the fire method.
setTimeout(function(){
$('button').fire('foo:bar', 'foobarbaz');
}, 10000);
// Let's listen for the 'foo:bar' event.
$('button').observe('foo:bar', function(evt){
alert(evt.memo); // => foobarbaz
});
The Prototype custom ‘dom:loaded’ event
Prototype 1.6.0 final also comes with the 'dom:loaded' event which is fired by the document object. This event’s fired when the DOM tree is loaded, without waiting for images. This event fires somewhat faster than the window load event, depending on the number of images on the page. The following ‘bonus’ example shows the usage of the ‘dom:loaded’ event:
// This global variable is set when the dom finishes loading.
var domloaded;
// This custom event is fired when the DOM's finished loading.
// dom:loaded event fires before the window load event.
Element.observe(document, 'dom:loaded', function(){
domloaded = new Date().getTime();
});
// Observing the plain old window load event.
Element.observe(window, 'load', function(){
var load = new Date().getTime();
alert(load - domloaded); // +-35 (ms)
});
There’s one particularity of Prototype’s new custom events system: the events bubble! (That feature requires namespacing so as not to conflit with native events).
As far as I know, other implementations of custom events are actually more of a publisher/receiver pattern (i.e. they don’t bubble).
Note that if you want to observe
dom:loaded, you’ll need to observe it ondocument, not onwindow.