Reputation: 1836
I encountered a problem today that i'm not sure how to deal with efficiently. As you can see in the code below there are three buttons, when one of them is clicked they all move to a designated spot, and then the button that was clicked changes color.
This was what I was hoping to achieve initially, however the background-color changes instantly without giving the buttons a chance to "arrive at their destinations". I tried to combat this by using a setTimeout(), but the nested function does not recognize the this
.
$('.groupOfButtons').on('click', function(){
$('#oneButton').animate({
left:"425px",
top:"-=24px"
}, 1000)
$('#anotherButton').animate({
left:"273px",
top:"+=5px"
}, 1000)
$('#oneMoreButton').animate({
left:"137px",
top:"+=34px"
}, 1000)
setTimeout(function(){
$(this).css({'background-color': 'green'})}, 1000) // here!
})
})
If someone could give me a workaround that would be great! But in the meantime I'm curious about double nested this
's. How would one use it within one or more functions? Is it possible?
Upvotes: 0
Views: 99
Reputation: 240968
Within the setTimeout
function callback, this
references the global window
object.
You need to capture the value of this
outside of that scope:
$('.groupOfButtons').on('click', function(){
var self = this;
$('#oneButton').animate({
left:"425px",
top:"-=24px"
}, 1000)
$('#anotherButton').animate({
left:"273px",
top:"+=5px"
}, 1000)
$('#oneMoreButton').animate({
left:"137px",
top:"+=34px"
}, 1000)
setTimeout(function(){
$(self).css({'background-color': 'green'});
}, 1000);
});
Also, as Félix pointed out in the comments, you can also change the value of this
by using the .bind()
method on the function:
setTimeout(function(){
$(this).css({'background-color': 'green'});
}.bind(this), 1000);
Upvotes: 6
Reputation: 19288
To fix the actual issue, keep a reference to which button was clicked, while this
still refers to it.
Also .... setTimeout()
will sort of do the job but leaves the timing somewhat to chance. For guaranteed timing, use promises and jQuery.when() to aggregate them.
$('.groupOfButtons').on('click', function() {
var clickedButton = $(this); // keep a reference to which button was clicked
var promise1 = $('#oneButton').animate({
left:"425px",
top:"-=24px"
}, 1000).promise();
var promise2 = $('#anotherButton').animate({
left:"273px",
top:"+=5px"
}, 1000).promise();
var promise3 = $('#oneMoreButton').animate({
left:"137px",
top:"+=34px"
}, 1000).promise();
$.when(promise1, promise2, promise3).then(function() {
clickedButton.css('backgroundColor', 'green')); // here use the reference made earlier.
});
});
This will guarantee that the color change happens when all the buttons have arrived at their new positions, even if some computer glitch delays one or all of them.
Upvotes: 1