.delayed() - A jQuery plug-in for delaying and debouncing events

.delayed() is a simple replacement for jQuery's .on() and it's derivative methods that lets you delay and even debounce an event handler. Delayed() is also great for hover intent and polling. If you've used on(), bind() or any of the other jQuery event methods, you already know how to use .delayed(). Unlike jQuery's .delay() method, .delayed() works with more than just animations; it works with entire events! Event better: It's fully chainable and context-aware.

Other methods of delaying or debouncing events using setTimeout can be difficult to use with the anonymous functions that are often used when binding events in jQuery, and you have to write custom code in order to stop or remove delays from your callbacks. With .delayed() everything is done for you.


Using .delayed() - A simple example...

// Binding a normal event handler
$('#MyButton').on('click', function() {
    alert("I was just clicked!");
});

// Binding a delayed event handler
$('#MyButton').delayed('click', 1000, function() {
	alert("I was clicked 1 second ago!");
});

That's it! Debouncing an event that fires too rapidly is just as simple...

// Bindind a normal event handler
$(window).on('scroll', function() {
    alert('I was scrolled!');
});

// Bindind a debounced event handler
$(window).debounce('scroll', function() {
    alert('I was scrolled!');
});

These are just simple examples but .delayed() is capable of so much more! If you're an advanced user, keep reading!




Why This Plug-In?

Many of the websites that I build require delayed events for things like hover-intent, polling, or debouncing. Instead of constantly approaching this on a case by case basis, I decided to tackle the problem in a highly reusable way, and ended up creating a jQuery plug-in.

Originally inspired by Paul Irish's debounce plug-in, my plug-in supplements jQuery.on() allowing entire events to be delayed and debounced.

Researching this eventually lead me to Ben Alman's jQuery.doTimeout() plugin. The problem with that plug-in was the learning curve that some developers had when using multiple timeouts, and when canceling timeouts. It also didn't seem to have any built-in way to remove the delay of the code execution without rebinding the event handler. (Something that would require duplicate code when using anonymous functions.)

As such, I decided to give my plug-in near identical syntax to jQuery's native jQuery.on() method, (which should make it very easy for developers to pick up.) I also added helpful method to rebind the event handler without the code execution delay. Existing code can be easily augmented to use delayed event handlers simply by changing the method name.




Delegated Events, Namespaces, Event Maps, and more!

Because .delayed() is based on core code from within jQuery itself, all of the features from .on() and .bind() supported. This includes

  • Delegating events with selectors
  • Using multiple event names and namespaces
  • Passing event-map objects
  • Passing data to the handler
  • Triggering the event using .trigger()

For example, this will work perfectly with .delayed()

$('#show_listing').delayed(
    'click.mycompany',		// Event Type
    2000,			// Delay in milliseconds
    'li input[type="button"]',	// CSS Selector
    {key: 'value'},		// Data to be passed to the handler
    function(event) {			
        alert('The data sent to me was: ' + JSON.stringify(arguments));
    }
);

Stopping Delayed Handlers and Removing Delays

Very similar to jQuery's .unbind() delayed handlers can be stopped at any time by calling .stopDelayed()

// Bind a delayed event handler
$('#MyButton').delayed('click', 1000, function() {
    alert("I was clicked 1 second ago!");
});

// Bind a click event handler to a button
$('#StopButton').on('click', function() {
    // Call .stopDelayed() to stop the delayed handler
    $('#MyButton').stopDelayed('click');
});

It's that simple! If you passed a selector to .delayed() you can pass that to .stopDelayed() to narrow the list of delayed handlers that will be stopped. You can even pass the handler itself to .stopDelayed() to stop a specific handlers.

Want to remove the delay from a handler? .removeDelay() rebinds your events (without changing the events internal guid,) so that it will fire immediately upon being triggered. It accepts the same parameters that .stopDelayed() uses, like so:

// Bind a delayed event handler
$('#MyButton').delayed('click', 1000, function() {
    alert("I was clicked!");
});

// Bind a click event handler to a button
$('#StopButton').on('click', function() {
    // Call .removeDelay() to remove the delay
    $('#MyButton').removeDelay('click');
});

Using .delayed() once with .delayedOne() and .delayedFirst()

This one is pretty simple: jQuery's .one() is exactly the same as .on() except that after it's been fired, it unbinds itself. You can do the same thing using .delayedOne() with all of the same parameters as .delayed()

If you only want the delay to occur once, but you want to keep the handler bound to your event, simply use .delayedFirst() as you would .delayed(). After the event has been triggered the first time, .delayedFirst() will call .removeDelay() on itself.


Event Propagation with .delayed()

Internally .delayed() creates a copy of your event handler, and calls it using setTimeout. Because it runs after the event was triggered, putting .stopPropagation() in your handler won't prevent the original event from propagating. To do this, replace the delay time (normally an integer of milliseconds) with an object, like this:

$('#MyButton').delayed('click', {delay: 1000, stopPropagation:true}, function() {
	alert("I was clicked!");
});

This supports . stopPropagation(), .stopImmediatePropagation(), and .preventDefault(). If you use .delayedFirst() or if you plan to use .removeDelay() on this event, you should put .stopProgagation() in your handler as well.




Documentation:

.delayed( events, delay-parameters [, selector] [, data], handler(eventObject) )
.delayed( events-map, delay-parameters [, selector] [, data] )

Accepts the same values as jQuery's .on() with the exception of delay-parameters.

delay-parameters An integer of milliseconds to delay the handler, or an object in the style of

{
    delay: 1000,
    stopPropagation: true,		// Optional
    stopImmediatePropagation: true,	// Optional
    preventDefault: true		// Optional
}
.

.delayedOne( events, delay-parameters [, selector] [, data], handler(eventObject) )

Bind a delayed handler to an event, which will only fire once.

See .delayed()

.delayedFirst( events, delay-parameters [, selector] [, data], handler(eventObject) )

Bind a delayed handler to an event. The handler will fire un-delayed after it is triggered the first time.

See .delayed()

.stopDelay( [eventType] [, handler(eventObject)] )

Stop a delayed handler from running after an event has been triggered. (This does not prevent the handler from running again if the event is triggered again.)

.removeDelayed( [eventType] [, handler(eventObject)] )

Re-binds the delayed handler so that it runs immediatly when the event is triggered.




Updates:

1.1.0 - 11/8/2012

Updated for jQuery 1.8.x to use the new internal data structure for events assigned to a given element.

.stopDelayed() and .removeDelay() now work correctly with mouseenter and mouseleave.




Comments:


Where to get it?

Download it here on GitHub!

About .delayed()

Introduction Basic Example Plug-In History Advanced Features Stopping & Removing Variations Propagation Documentation Updates
Current version: 1.1.0
Tested with jQuery 1.8.2
Updated 11/8/2012
Released 5/24/2012