0

I am using the jQuery animate method in which I want to call a function when the animation is complete. Since the function is called several times in a loop, I need to access some variable but do not know how to do this (something to do with closures I guess).

I have :

while (i<numberofTimeIntervals)
{   
     // some calculations here
     xPos = initialPosX + x + "px";
     yPos = initialPosY - y + "px";

     $("#object").animate({left: xPos},10).animate({top: yPos},10, function(){ console.log(xPos) });  <-- what I want here is the access to xPos and yPos

     i = i + 1;
}

So I need to have access to xPos and yPos at the time it is calculated as the callback is called at a later time.

JD.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
JD.
  • 15,171
  • 21
  • 86
  • 159
  • You should have the variable there. It's in the closure's scope... what's it doing? – Groovetrain Mar 09 '11 at 14:41
  • possible duplicate of [How do I pass the value (not the reference) of a JS variable to a function?](http://stackoverflow.com/questions/2568966/how-do-i-pass-the-value-not-the-reference-of-a-js-variable-to-a-function) – Andy E Mar 09 '11 at 14:45

5 Answers5

3

Use a second closure:

while(i<numberofTimeIntervals)
{
    var xPos = initialPosX + x + "px";
    var yPos = initialPosY - y + "px";

    (function(xPos) {
        $('#object').animate({left: xPos},10).animate({top: yPos},10, function(){  console.log(xPos) });
    })(xPos);

    i++;
}

Explanation: JavaScript has no block scope, just a function scope. So your callback function's closure saves the variable (not its value) xPos. So at the end of the loop, the saved variable - which is the same one as the loop variable - has the final value. By wrapping the call in an anonymous function which gets the variable passed as an argument, it's now saved as a new variable which will not be modified anymore.


Btw, if you had access to JavaScript 1.7 (unfortunately only few browsers support it) you could also use let xPos instead of var xPos to move it into the block scope.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • Whoever downvoted: Please leave a comment. From what I know this is the correct way to deal with closures inside of loops. – ThiefMaster Mar 09 '11 at 14:47
  • JavaScript has no block scope, just a function scope. So your callback function's closure saves the variable (not its value) `xPos`. So at the end of the loop, the saved variable - which is the same one as the loop variable - has the final value. By wrapping the call in an anonymous function which gets the variable passed as an argument, it's now saved as a new variable which will not be modified anymore. – ThiefMaster Mar 09 '11 at 15:04
  • @ThiefMaster: Imo you should put your comment in the answer, makes it even better ;) And I would say it is not a closure as you are not accessing the variables of the parent scope.... but that is nitpick. +1 to compensate -1... – Felix Kling Mar 09 '11 at 15:11
  • @felix: added it to my answer – ThiefMaster Mar 09 '11 at 15:12
  • @JD: since it fixed your issue, please don't forget to accept the answer by clicking on the checkmark icon – ThiefMaster Mar 09 '11 at 15:13
  • 1
    You can't really attribute the lack of `let` support to IE - no versions support it including IE 9 - `let` is a Mozilla extension to the ECMAScript specification which JavaScript is based upon. FWIW, Chrome and plenty other browsers don't support it either, useful as it may be. – Andy E Mar 09 '11 at 15:22
1

try this:

while (i<numberofTimeIntervals) {   

   //<!-- some calculations here--->

   (function(){
       var 
          xPos = initialPosX + x + "px",
          yPos = initialPosY - y + "px";

       $("#object")
          .animate({left: xPos},10)
          .animate({top: yPos},10, function(){  console.log(xPos) });  
       //<-- what I want here is the access to xPos and yPos

   })();

   i = i + 1;
}
andres descalzo
  • 14,887
  • 13
  • 64
  • 115
0

You have a closure there. You should have access to both these variable already. Can you post the exact code pleas?

Nikhil
  • 3,304
  • 1
  • 25
  • 42
-1

I got it to work this way: http://jsfiddle.net/gailbear/WbNdx/6/

function printme(xpos){
    console.log(xpos);
}

while (i < numberofTimeIntervals) {

    var xPos = initialPosX + x + "px";
    var yPos = initialPosY - y + "px";

    $("#object").animate({
        left: xPos
    }, 10).animate({
        top: yPos
    }, 10, printme(xPos));

    i = i + 1;
}

The first error I got was "don't define functions within a loop". Let me know if that code helps.

gailbear
  • 519
  • 3
  • 13
  • Sorry to say, but that's completely wrong. You pass the (undefined) return value of a new function instead of a function as the callback. So you execute the function immediately instead of when the callback should be called. – ThiefMaster Mar 09 '11 at 15:05
-2

You can define them as global variables, meaning outside of any function or object. Then you can access them from anywhere.

Eugene msc
  • 360
  • 2
  • 8