Reputation: 322
I have a code:
$("#button").click(function () {
for (var i = 0; i < 4; i++) {
setTimeout(function () {
$(".rows:eq("+i+")").css("background-color", "blue");
},500);
}
});
For some reason only the fifth element gets background-color grey. What is wrong?
Upvotes: 0
Views: 44
Reputation: 1
Try using .delay()
, .queue()
, recursively call click
handler with incremented .index()
of .row
as parameter after initially setting .eq()
to event.data
: 0
// `0` : `event.data`
$("#button").click(0, function re(event) {
var i = typeof event.data === "number" ? event.data : event;
$(".row").eq(i).delay(500).queue(function() {
$(this).css("background-color", "blue");
if ($(this).index(".row") < 3) {
re(i + 1)
}
})
})
.row {
color:orange;
width:36px;
padding:8px;
font-weight:bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button id="button">click</button>
<span class="row">0</span>
<span class="row">1</span>
<span class="row">2</span>
<span class="row">3</span>
<span class="row">4</span>
Upvotes: 0
Reputation: 1998
It has to do with the scoping of the i
variable. It is bound to the for loop, not to the function invoked by setTimeout. Basically, when the delayed function is invoked, i
is already increment to 4. In order to bind the current loop value of i
, call another function. i
is placed on the function stack and therefore the value if preserved.
It depends what kind of behavior your're looking for, but if you want to change the css of all elements at once @Josh's comment is the best.
$("#button").click(function () {
setTimeout(function (){
for (var i = 0; i < 4; i++) {
$(".rows:eq("+i+")").css("background-color", "blue");
}
,500);
});
Otherwise try:
bindItoFunc = function (i) {
return function (){
$(".rows:eq("+i+")").css("background-color", "blue");
};
}
$("#button").click(function () {
for (var i = 0; i < 4; i++) {
setTimeout(bindItoFunc(i),500);
}
});
Maybe a more elegant solution is to bind i
as the this
value of the function.
bindItoFunc = function () {
$(".rows:eq("+this+")").css("background-color", "blue");
}
$("#button").click(function () {
for (var i = 0; i < 4; i++) {
setTimeout(bindItoFunc.bind(i),500);
}
});
Question asker indicated that the background should change in order. In that case, change the waitMs based on i
.
bindItoFunc = function () {
$(".rows:eq("+this+")").css("background-color", "blue");
}
$("#button").click(function () {
for (var i = 0; i < 4; i++) {
setTimeout(bindItoFunc.bind(i),500+(100*i));
}
});
Upvotes: 2