Reputation: 18205
I'm using jquery and what I'm doing is binding the toggle method to a number of buttons on a webpage. It looks something like this
$('.button').toggle(function(){
// first function
}, function(){
// second function
});
However, there are animation in both of those functions. So a user can click the button while the first or second function is executing. And this messes up the order of the HTML elements and may make them move to the end of the page. Because essentially what these functions do is move one element to the end on the first click, and on the other click move it back where it originally was.
Of course, it is difficult to click the button once it is moving around the page. But it's possible.
Upvotes: 2
Views: 1349
Reputation: 3780
Seems like you'll be happier implementing your own toggle. Toggle really only works for cases with 0 additional logic.
$('.button').click(
function () {
if( $(self).is(":animated") {
return false;
}
if($(self).is(".rolledup")) {
self.apply(roll_window_down);
} else {
self.apply(roll_window_up);
}
});
function roll_window_up() {
$(self).addClass( 'rolledup' );
// first function
}
function roll_window_down() {
$(self).removeClass( 'rolledup' );
// first function
}
Upvotes: 0
Reputation: 9305
You need a queue. You can build one with a semaphore variable, but jQuery already provides one, so maybe you want to use it:
$('.button').toggle(function() {
$(document).queue("foo", function() {
...
});
}, function() {
$(document).queue("foo", function() {
...
});
});
jQuery normally uses the "fx" queue to serialize animations, but you can use this "foo" queue for whatever you want.
The queue can be put on any object, so maybe you want to put it on the container that has all the .button
objects in it. You cannot put it on the button (this) themselves, or you'll be back to where you're at now.
Once you've done that, all you really need to do is abort an animation. This can be done by expressly emptying the "fx" queue, or you can use $('.button').stop();
to stop all the old animations.
Upvotes: 0
Reputation: 189505
You need to place the two functions you pass to toggle in a context in which you can hold a flag to control function entrance:-
(function() {
var toggling = false;
$('.button').toggle(function(){
if (!toggling) {
toggling = true;
// first function
toggling = false;
} else {
// whatever you want to happen if re-entrance attempted
}
}, function(){
if (!toggling) {
toggling = true;
// second function
toggling = false;
} else {
// whatever you want to happen if re-entrance attempted
}
})
)();
N.B. This serialises all toggles of elements that have the .button
class. IOW there is only one toggling
flag for all buttons. If you want each button to have its own toggling flag:-
$('.button').each(function() {
var toggling = false;
$(this).toggle(function(){
if (!toggling) {
toggling = true;
// first function
toggling = false;
} else {
// whatever you want to happen if re-entrance attempted
}
}, function(){
if (!toggling) {
toggling = true;
// second function
toggling = false;
} else {
// whatever you want to happen if re-entrance attempted
}
});
);
Upvotes: 0
Reputation: 268424
You could use a flag. Set a flag 'isAnimating' to true
when an animation begins, and false when it ends. Any subsequent animation can only proceed if this value is false
.
You could also possibly check to see if the :animated selector applies to the owner of the event. And base your decisions off of that.
Upvotes: 5
Reputation: 11287
You could use a bool as a semiphore.. Obviously, this is in no way secure, but javascript doesn't really support locking, so you could easily have deadlocks and / or race conditions with this approach, but it will work 99,9% of the times :)
Upvotes: 3