Monday, March 29th, 2010

jQuery Special Events; Virtually… not in Real Life

Category: JavaScript, jQuery

<>p>Ben Alman has a mother of a post on his special events work for jQuery. I have a special penchant for custom events and the like, even though I have abused them just as I did in the old days of AOP! :)

What are special events?

The jQuery special events API is a fairly flexible system by which you can specify bind and unbind hooks as well as default actions for custom events. In using this API, you can create custom events that do more than just execute bound event handlers when triggered—these “special” events can modify the event object passed to event handlers, trigger other entirely different events, or execute complex setup and teardown code when event handlers are bound to or unbound from elements.

He does into intrigue detail on the API and gets to show you how to implement the hello world of custom events: tripleclick:

javascript
< view plain text >
  1. (function($){
  2.  
  3.   // A collection of elements to which the tripleclick event is bound.
  4.   var elems = $([]);
  5.  
  6.   // Click speed threshold, defaults to 500.
  7.   $.tripleclickThreshold = 500;
  8.  
  9.   // Special event definition.
  10.   $.event.special.tripleclick = {
  11.     setup: function(){
  12.       // Initialize the element plugin data, including clicks counter and
  13.       // last-clicked timestamp.
  14.       $(this).data( 'tripleclick', { clicks: 0, last: 0 } );
  15.  
  16.       // Add this element to the internal collection.
  17.       elems = elems.add( this );
  18.  
  19.       // If this is the first element to which the event has been bound,
  20.       // bind a handler to document to catch all 'click' events.
  21.       if ( elems.length === 1 ) {
  22.         $(document).bind( 'click', click_handler );
  23.       }
  24.     },
  25.     teardown: function(){
  26.       // Remove all element plugin data.
  27.       $(this).removeData( 'tripleclick' );
  28.  
  29.       // Remove this element from the internal collection.
  30.       elems = elems.not( this );
  31.  
  32.       // If this is the last element removed, remove the document 'click'
  33.       // event handler that "powers" this special event.
  34.       if ( elems.length === 0 ) {
  35.         $(document).unbind( 'click', click_handler );
  36.       }
  37.     }
  38.   };
  39.  
  40.   // This function is executed every time an element is clicked.
  41.   function click_handler( event ) {
  42.     var elem = $(event.target),
  43.  
  44.       // Get plugin data stored on the element.
  45.       data = elem.data( 'tripleclick' );
  46.  
  47.     // If more than `threshold` time has passed since the last click, reset
  48.     // the clicks counter.
  49.     if ( event.timeStamp - data.last > $.tripleclickThreshold ) {
  50.       data.clicks = 0;
  51.     }
  52.  
  53.     // Update the element's last-clicked timestamp.
  54.     data.last = event.timeStamp;
  55.  
  56.     // Increment the clicks counter. If the counter has reached 3, trigger
  57.     // the "tripleclick" event and reset the clicks counter to 0. Trigger
  58.     // bound handlers using triggerHandler so the event doesn't propagate.
  59.     if ( ++data.clicks === 3 ) {
  60.       elem.trigger( 'tripleclick' );
  61.       data.clicks = 0;
  62.     }
  63.   };
  64.  
  65. })(jQuery);

There is a lot in his article, so give it a once over.

Related Content:

4 Comments »

Comments feed TrackBack URI

Nice work, Ben! It’s encouraging to see this technique being more broadly adopted and supported by js libs. Also in YUI 3, with new API Y.Event.define( name, { config } ); in 3.1.

It’s a very useful approach to make DOM oriented code more readable by labeling common user interaction patterns.

Kudos

Comment by lsn — March 29, 2010

Hey, where is my previous comment? This technique will never work reliable! Click event will not be fired repeatedly in time less than 200ms. Mousedown does not help too, because in Internet Explorer, second mousedown is replaced with selectstart.

Comment by steida — March 30, 2010

Steida, the event examples I use in the article are more theoretical than practical – I’ve actually linked to fully unit-tested, complete plugins where appropriate, and explained caveates and gotchas like this IE issue in the article.

Thanks!

- Ben

Comment by benalman — March 30, 2010

Still, selectstart event is not always fired, on anchors for example.

Comment by steida — April 1, 2010

Leave a comment

You must be logged in to post a comment.