Shvalb
Shvalb

Reputation: 1923

Pass parameter to animate callback function

I have the following jQuery snippet and I'm trying to pass a parameter to the function of animate method but can't get it right.

function move() {

    var points = [13, 8, 5];

    for(var pointIdx=0; pointIdx < points.length-1; pointIdx++) {
        ..
        ..

        // animate move.        
        $('#my_id', gameWindow.document).animate({ left: "50px" ,top:  "50px" }, 1500, 'linear', 
            function(pointIdx) {
                console.log("Animation: Iteration=" + pointIdx); // pointIdx is undefined at this point, why?
               ...
               ...
            }
        )
    }
}

How to do it right?

Thanks!

Upvotes: 3

Views: 2329

Answers (2)

inorganik
inorganik

Reputation: 25525

The problem is timing - the animation callback happens after 1500 ms, but your for loop completes almost instantly. You need to rewrite it like this:

var points = [13, 8, 5];
var pointIdx = 0;

function animateForPointIndex(index) {
    $('#my_id').animate({
        left: "50px",
        top: "50px"
    }, 1500, 'linear', function () {
        pointIdx++;
        if (pointIdx < points.length) {
            console.log("Animation: Iteration=" + pointIdx);
            // do what you need to here 
            animateForPointIndex(pointIdx);
        }
    });
}
animateForPointIndex(0);

The animate function is called recursively after each completion, only if the point index is less than the length of the points array.

Upvotes: 2

Travis J
Travis J

Reputation: 82267

pointIdx is undefined because the complete callback for jQuery's animation does not have any parameters available to use.

http://api.jquery.com/animate/

complete
Type: Function()
A function to call once the animation is complete.

So when you include the parameter pointIdx in the animate function complete callback like this

function(pointIdx) {

you are overwriting the variable pointIdx. Because JavaScript uses a stack of lexical variable environments, pointIdx is pushed on to the stack with the value passed in from the complete callback. This value is undefined, and when you try to read the value of the variable pointIdx inside of the execution context of the complete callback, it gets the top most value of the stack, which is undefined. This is why pointIdx is undefined here.

In order to store the value of pointIdx inside of this callback you need to remove it from the parameters, and also you need to close over it with an IIFE.

jsFiddle Demo

for(var pointIdx=0; pointIdx < points.length; pointIdx++) {
    ..
    ..

    // animate move.        
    //close over pointIdx
    (function(pointIdx){
    //now the execution context is inside of the anonymous function
    //and the value of pointIdx in the loop is stored in
    //variable pointIdx (same name for consistency) is at the top of that variable environment
    $('#my_id', gameWindow.document).animate({ left: "50px" ,top:  "50px" }, 1500, 'linear', 
        function() {
            console.log("Animation: Iteration=" + pointIdx); // pointIdx will now contain the iteration value from the for loop
           ...
           ...
        }
    )
    })(pointIdx);
}

Upvotes: 4

Related Questions