jQuery+: $.when() to bind button clicks
Builds promises for 5 button clickHandlers. Uses $.when() to batch process a grouped response when all buttons have been clicked.
by mrrodd
HTML
<link rel="stylesheet" href="http://www.gridlinked.info/cdn/css/jsFiddle.css">
<script src="http://www.gridlinked.info/cdn/highlighter/head.load.min.js"></script>
<script src="http://www.gridlinked.info/cdn/highlighter/head_highlighter.js"></script>
<body>
<div id="body">
<div id="header"></div>
<div id="contents">
<div id="intro">
<p>
Demonstration of jQuery plugins, <strong><a href="http://api.jquery.com/category/deferred-object/" target="_blank">$.when( )</a></strong>, and Deferred(s).
</p>
</div>
<h2><code><span class='code'>$.when(...targets):Promise</span></code></h2>
<br/>
<div class="contents">
<div class="bullet">
<div class="description">
jQuery has a function <code><span class='code'>$.when()</span></code> that will watch one or more target
promises and/or functions.
Target functions included in the argument list are internally wrapped in their
own promises. Targets functions are immediately invoked and may optionally return their own promises.
<br/><br/>
All promises are processed in parallel as a batch collection.
Only <code><span class='code'>$.when()</span></code> all promises individually resolve does the wrapper
<code>promise</code> itself resolve.
In contrast, if any target promises reject then the <code><span class='code'>$.when()</span></code>
promise immediately rejects.
<br/><br/>
And since the <code><span class='code'>$.when()</span></code> function returns a <code>promise</code>,
developers can easily use the <span class='jquery'>Promise::pipe()</span> and
<span class='jquery'>Promise::done()</span>...
JavaScript
( function($) {
/**
* jQuery Plugin `allClicked` uses the $.when() feature to watches
* for a collection of items to be all clicked
*
* Returns a group of promises that are resolved as a group when all
* of the selected elements have been clicked at least once.
*
*/
$.fn.allClicked = function() {
var promises = this.map( function() {
// for each element, create a Promise to `respond to a future click`
// NOTE: but only respond on the first click for each button.
var ele = $(this); // now get the jQuery proxy for this element
return $.Deferred( function(dfd){
ele.one( 'click', function() {
ele.fadeTo(300,.2);
dfd.resolve( );
});
}).promise();
});
// We can't actually pass an array to $.when,
// but we can .apply() an array of promises:
return $.when.apply( $, promises );
};
}(jQuery));
// *****************************************
// Now let's configure page-specific features
// *****************************************
( function($) {
/**
* @see http://api.jquery.com/promise/#example-1
*/
$( "button" ).allClicked().then( function() {
// When all the buttons have been clicked once, then do
// something...
var imgHTML = '<img id="cheers" src="http://images.gridlinked.info/1.jpg" />';
$('#applause')
.append( imgHTML )
.fadeIn(500)
.delay(1000)
.fadeOut(1500)
.promise()
.done( function() {
$("#controls").append( "<br/><br/>Finished!" );
});
/**
* Approach #1 - using .promise() in the chain
*
$.when( $('#applause') )
.done( function(elements){
...