Special Events: The Changes in 1.4.2
jQuery’s event system has seen incredible feature growth over the years and with that growth came some pains. jQuery 1.4.2 included a much needed overhaul of the event system. This also brought some backwards incompatible changes to the two new special event hooks added in 1.4. I previously blogged about these two new special event hooks: add
and remove
. These two events hooks brought lots of power by being able to manipulate the event details for each event handler registered. This is different from the existing setup
and teardown
hooks (added in 1.2.2) that only worked once per an event, per an element.
I’ve written about Special Events a few times now. I recommend going back and reading the previous posts for more details about Special Events, if you haven’t already done so. First there was the introductory blog post, then the post about the add
and remove
hooks, and finally a post about automating with special events.
The Changes
First lets rundown the changes which at first may seem more complicated than they actually are. It all has to do with how jQuery internally stores the details related to an event per an element (.data('events')
). Since the beginning jQuery stored event details on the handler function itself in an object. Now the event details are stored in an object within an array. This provided several benefits, not the least of these being guaranteed event order in all browsers (which has been a pretty highly desired feature). However, the add
and remove
callback now get the object with the event details passed instead of the individual arguments as before.
Lets take a look at the two call signatures to make this a little more clear. I’m going to use the same example that I used in the previous blog post about these new event handlers. I’m only showing the add
and remove
hooks since the setup
and teardown
are unmodified.
// In jQuery 1.4 and 1.4.1
jQuery.event.special.multiclick = {
add: function( handler, data, namespaces ) {
// called for each bound handler
},
remove: function( namespaces ) {
// called for each bound handler
}
};
// In jQuery 1.4.2+
jQuery.event.special.multiclick = {
add: function( details ) {
var handler = details.handler,
data = details.data,
namespace = details.namespace;
},
remove: function( details ) {
var handler = details.handler,
data = details.data,
namespace = details.namespace;
}
};
The Updated multiclick
Special Event
If you remember the multiclick
event, it had the ability to be configurable per a handler. The usage looks like this.
$('div')
.bind("multiclick", { threshold: 5 }, function( event ) {
alert( "Clicked 5 times" );
})
.bind("multiclick", { threshold: 3 }, function( event ) {
alert( "Clicked 3 times" );
});
The threshold
passed in the data for the event handler is how many times the element must be clicked before the event handler fires. Most of the functionality for this special event was in the add
hook. It would replace the handler with a handler that would track the number of clicks. Here is what the add
hook for this event looked like before.
jQuery.event.special.multiclick = {
add: function( handler, data, namespaces ) {
// get the required number of clicks from data
var threshold = data && data.threshold || 1,
// number of clicks
clicks = 0;
// return a new function that will become the handler
return function( event ) {
// increase number of clicks
clicks += 1;
if ( clicks === threshold ) {
// required number of clicks reached, reset
clicks = 0;
// call the actual supplied handler
handler.apply( this, arguments );
}
}
},
...
};
And here is how it looks in 1.4.2.
jQuery.event.special.multiclick = {
add: function( details ) {
var handler = details.handler,
data = details.data,
threshold = data && data.threshold || 1,
clicks = 0;
// replace the handler
details.handler = function(event) {
// increase number of clicks
clicks += 1;
if ( clicks === threshold ) {
// required number of clicks reached, reset
clicks = 0;
// call the actual supplied handler
handler.apply( this, arguments );
}
};
},
...
};
The rest of the special event remains the same.
Support 1.4+
If you need to support 1.4, 1.4.1, and the new way in 1.4.2 then here is some sample code to help you make the transition. This sample code was written by Ben Alman (whom I hear is working on an uber Special Events article).
// 1.4, 1.4.1 and 1.4.2 (existing plugins, update for 1.4.2 this way)
$.event.special.foo = {
add: function( handleObj ) {
// Do something when event is bound here!
var old_handler;
function new_handler(event) {
// Modify event object here!
old_handler.apply( this, arguments );
};
// This may seem a little complicated, but it normalizes the special event
// .add method between jQuery 1.4/1.4.1 and 1.4.2+
if ( $.isFunction( handleObj ) ) {
// 1.4, 1.4.1
old_handler = handleObj;
return new_handler;
} else {
// 1.4.2+
old_handler = handleObj.handler;
handleObj.handler = new_handler;
}
}
};