1

I'm trying to execute a specific function once some processes finished executing.

My specific example refers to a number of animate() methods after which I want to call another function, however this function should only be called once the animate() methods finished processing:

var testObject = {
    methodOne : function(callbackMethod) {
        $('#item').animate({ 'paddingLeft' : '20px'}, { duration: 200, queue: false });
        $('#item2').animate({ 'paddingLeft' : '30px'}, { duration: 200, queue: false });
        $('#item3').animate({ 'paddingLeft' : '40px'}, { duration: 200, queue: false });
        testObject.callbackMethod();
    },
    run : function() {
        alert('done');
    }
};

$(function() {

      testObject.methodOne(run);

});

Any idea how can I achieve this?

4 Answers 4

7

Provided you are using jQuery >= 1.5, then you should use the Deferred-functionality:

var testObject = {
    methodOne : function($elements, callbackMethod) {
        $elements.each(function (i) {
           $(this).animate({ 'paddingLeft' : (10 + (10*i)) + 'px'}, { duration: 200 * i, queue: false });
        });
        $elements.promise().done(callbackMethod);
    },
    run : function() {
       $('.wrapper').append('<span>Finished!</span>');
    }
};

$(function() {
  testObject.methodOne($('#item, #item2, #item3'), testObject.run);
});

jsFiddle for this example: http://jsfiddle.net/3Z4zu/

A cleaner/refactored version could look like this:

var testObject = {
    methodOne : function($elements, callbackMethod) {
        $elements.each(function (i) {
           $(this).animate({ 'paddingLeft' : (10 + (10*i)) + 'px'}, { duration: 200 * i, queue: false });
        });
        $elements.promise().done(callbackMethod);
    },
    run : function() {
       $('.wrapper').append('<span>Finished!</span>');
    }
};

$(function() {
  testObject.methodOne($('#item, #item2, #item3'), testObject.run);
});

http://jsfiddle.net/3Z4zu/1/

Sign up to request clarification or add additional context in comments.

1 Comment

Nice, I didn't know about the Promise objects.
3

You can define a custom event to be fired when an animation stops, for example:

$("body").bind("animationsComplete", function() {
  testObject.completed++;
  if (testObject.completed == testObject.needToComplete) {
    testObject.run();
  }
});

In each of your functions you should trigger that event:

var testObject = {
    needToComplete : 3,
    completed : 0,
    methodOne : function(callbackMethod) {
        $('#item').animate({ 'paddingLeft' : '20px'}, { duration: 200, queue: false ,complete : function(){
            trigger("animationsComplete");
        }});
        $('#item2').animate({ 'paddingLeft' : '30px'}, { duration: 200, queue: false ,complete : function(){
            trigger("animationsComplete");
        }});
        $('#item3').animate({ 'paddingLeft' : '40px'}, { duration: 200, queue: false ,complete : function(){
            trigger("animationsComplete");
        }});
    },
    run : function() {
        alert('done');
    }
};

EDIT: I understand that I lost some functionality of your original code (defining which function to be called as callback) but I think you'll know basically what I had in mind.

1 Comment

+1 because using custom events is a good alternative to using Deferred-functionality
1

You can count the animate function calls and decrement that number in each animation callback. In the callbacks, if all the other animations have finished you call the "master" callback :

var testObject = {
    methodOne : function(callbackMethod) {
        var animationsCount = 3;
        $('#item').animate({ 'paddingLeft' : '20px'}, { duration: 200, queue: false ,complete : function(){
            if(--animationsCount == 0)
                testObject[callbackMethod]();
        }});
        $('#item2').animate({ 'paddingLeft' : '30px'}, { duration: 200, queue: false ,complete : function(){
            if(--animationsCount == 0)
                testObject[callbackMethod]();
        }});
        $('#item3').animate({ 'paddingLeft' : '40px'}, { duration: 200, queue: false ,complete : function(){
            if(--animationsCount == 0)
                testObject[callbackMethod]();
        }});
    },
    run : function() {
        alert('done');
    }
};

$(function() {

      testObject.methodOne('run');

});

Comments

1

You could have all of the success callbacks from each animate function increase a counter and call the same function (your callbackMethod).

In callbackMethod, you check to see if the counter has hit 3 and then only perform your desired code if it has.

Or work the opposite way from 3 down to 0, or 3 separate booleans, you've got many options to you at that point.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.