Using "for" loop to build jquery queue

I am trying to learn jquery queue. Everything works when I add each function to the queue manually:

$("#victory-gradient--r")
	      .queue(function(next) {
	        $(this).css({transform: "translate(-"+gradientSlowLoc+"px)", "-webkit-transform": "translate(-"+gradientSlowLoc+"px)", "transition-duration": gradientSpeed0 + "ms", "-webkit-transition-duration": gradientSpeed0 + "ms"}).one(TRANSITION_END, next);
	      })
	      .queue(function(next) {
	        $(this).css({transform: "translate(-"+gradientFastLoc+"px)", "-webkit-transform": "translate(-"+gradientFastLoc+"px)", "transition-duration": gradientSpeed1 + "ms", "-webkit-transition-duration": gradientSpeed1 + "ms"}).one(TRANSITION_END, next);
	      })
	      .queue(function(next) {
	        $(this).css({transform: "translate(-"+gradientFinalLoc+"px)", "-webkit-transform": "translate(-"+gradientFinalLoc+"px)", "transition-duration": gradientSpeed2 + "ms", "-webkit-transition-duration": gradientSpeed2 + "ms"}).one(TRANSITION_END, next);
	      });

but when I try to add them with a for loop, only the first one ever plays:

var gradientLocs = [gradientSlowLoc, gradientFastLoc, gradientFinalLoc];
var gradientSpeeds = [gradientSpeed0, gradientSpeed1, gradientSpeed2];
	    
	    
	    for (var i=0; i < 3; i++) {
	      $("#victory-gradient--r").queue(function(next) {
	        $(this).css({transform: "translate(-"+gradientLocs[i]+"px)", "-webkit-transform": "translate(-"+gradientLocs[i]+"px)", "transition-duration": gradientSpeeds[i] + "ms", "-webkit-transition-duration": gradientSpeeds[i] + "ms"}).one(TRANSITION_END, next);
	      });
	    }

I’ve seen people build jquery queues with loops before, including in a couple answers found here:

What am I doing wrong?

Classic!

Your for loop completes before the queue starts, so i is not what you’re expecting. You need to cache the counter. I would do this with an IIFE

for (var i=0; i < 3; i++) {
  (function() {
    var count = i; //<- This will store the value you want for the queued function
    $("#victory-gradient--r").queue(function(next) {
    $(this).css({transform: "translate(-"+gradientLocs[count]+"px)", "-webkit-transform": "translate(-"+gradientLocs[count]+"px)", "transition-duration": gradientSpeeds[count] + "ms", "-webkit-transition-duration": gradientSpeeds[count] + "ms"}).one(TRANSITION_END, next); //<- Change all references to i
  });
  })()
}

Thank you very much. Can you help me understand why it’s necessary to use count instead of i? Why would they both not do the same thing, if each time the function runs, the value of count and i are the same?

Here’s what’s happening:

forloop i=0
$("#victory-gradient--r").queue(queueFunction) // <- The function queueFunction is added to the queue, but not run yet
forloop i=1
$("#victory-gradient--r").queue(queueFunction) // <- Again, added to the queue, but not run yet.  
forloop i=2
$("#victory-gradient--r").queue(queueFunction)
//...

// Time to run the queued function
queueFunction() // <- The function is depending on the variable i, and it's different from when the function was queued

Each time the loop iterates, it adds your function to the queue. Notice that i is changing before the queued function is run. When the loop is complete and the functions are started, i will not be the same value as it was when the function was queued. In JavaScript, we can wrap code in a function, and that code will have access to all of the function’s variables. This is why we have the count variable inside of a function that gets run immediately. It’s storing the value of i that the queued function is going to need.

1 Like