Question

My problem is when I add a:

.done(function() {
  innerDef.resolve();                    
});

in the "animate" function, it don't work as I wanted.
I just want the function to wait until the animation finishes, like this:

$('#anim_vision').showThis().done(function(){
   alert('task finished!');
});

My full plugin code:

(function ($) {

    $.fn.extend({    
        showThis: function (options) {    
            var def = $.Deferred();

            var options = $.extend(options);
            var deferredList = [];

            this.each(function () { 
                var innerDef = $.Deferred();
                deferredList.push(innerDef.promise());

                $( this )
                .children('.texto')
                .removeClass('opacity_none')
                .css('display','block');

                $( this )
                .animate({'height':'100%'}, 900, 'easeOutQuad')
                .done(function() {
                    innerDef.resolve();                    
                });
                });

            $.when.apply($, deferredList).done(function() {
               def.resolve(); 
            });

            return def.promise();
        }
    });
})(jQuery);

I really need help, please!

Was it helpful?

Solution

A regular jQuery object doesn't have a .done() method. You would need to call .promise() to get the promise object for the animation by changing this:

            .animate({'height':'100%'}, 900, 'easeOutQuad')
            .done(function() {
                innerDef.resolve();                    
            });

to this:

            .animate({'height':'100%'}, 900, 'easeOutQuad')
            .promise()
            .done(function() {
                innerDef.resolve();                    
            });

But, you can simplify things by just using the promise directly rather than making your own innerDef.


Simplifying things even further, you don't need to make your own deferred either because you can just return the promise from $.when():

(function ($) {

    $.fn.extend({    
        showThis: function (options) {    
            var options = $.extend(options);
            var promiseList = [];

            this.each(function () { 

                $( this )
                    .children('.texto')
                    .removeClass('opacity_none')
                    .css('display','block');

                // run the animation,
                // get a promise object for the animation queue,
                // put it in our list of promises
                promiseList.push(
                     $( this )
                     .animate({'height':'100%'}, 900, 'easeOutQuad')
                     .promise()
                );
            });

            // return a new promise that is resolved 
            // when all the animations are done
            return $.when.apply($, promiseList);
        }
    });
})(jQuery);

After further research, you can simplify this even more to this:

jQuery.fn.extend({    
    showThis: function () {    
        return (this
          .children('.texto')
          .removeClass('opacity_none')
          .css('display','block')
          .animate({'height':'100%'}, 900, 'easeOutQuad')
          .promise()
        );
    }
});

Further changes:

  1. All the jQuery methods you are calling already iterate the whole collection so you don't need to iterate them manually with this.each().
  2. You aren't using the options argument so you can remove that.
  3. You don't have any persistent state variables so you don't need the function wrapper around it to isolate them.
  4. jQuery's .promise() resolves when the entire collection is done animating so it does that work for you. You don't need your own $.when() or your own promise array. You can just return the .promise() that comes after the .animate() and it will resolve when all the animations are done.

You can see this demo to see how .promise() waits for the entire collection to be done animating: http://jsfiddle.net/jfriend00/Erq5Q/.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top