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 SamsChoice

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){ 
               ...