I have next function:
function clearWorkingArea() {
$('.extensionText').children('span').fadeOut(600, function() { $(this).remove() });
$('ul.texts').fadeOut(600, function() { $(this).empty() });
$('.buttonsDiv').fadeOut(600, function() { $(this).remove() });
$('.processingDiv').fadeOut(600, function() { $(this).remove() });
}
I would like to call another function only after all animations in this function are finished.
I tried :
$.when(clearWorkingArea()).done(function() {...});
Also:
clearWorkingArea().promise().done(function() {...});
No luck, it is still not working properly.
Is there is a way, instead of callback hell of fades, to do such function behavior?
Update: just double checked jquery, animations can return a promise. I initially just did promise, but to get a promise with jquery you do promise(). So you don't need the helper function after all.
Below is an example.
Also if you have multiple selectors doing the same thing, you can combine.
eg. below .two & .three fadeOut at 600ms, but I've made .one fadeOut over 1000ms. Also added a none-existent selector to make sure things still work.
Promise.all(
[
$('.one').fadeOut(1000, function () {
$(this).empty(); }).promise(),
$('.two,.three').fadeOut(600, function () {
$(this).empty(); }).promise(),
$('.not-exist').fadeOut(600, function () {
$(this).empty(); }).promise()
]
).then(function () {
console.log('all done');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one">
Three 1000 ms
</div>
<div class="two">
One 600 ms
</div>
<div class="three">
Two 600 ms
</div>
clearWorkingArea only starts the animations, but these animations are all async.
At the end of clearWorkingArea, your animations are unlikely to be over.
You have to fetch a promise for each animation and then use Promise.all to trigger your code when all promises are over.
According to the documentation, you can get the promise by using the start parameter in the options of fadeOut like methods:
jQuery fadeOut()
Hope this helps!
How about we apply some simple logic like this.
function doWorkWhenAllFinished(counter) {
if (counter == 4) {
//All fade animations have been complete.
//Good to go...
}
}
function clearWorkingArea() {
var counter = 0;
$('.extensionText').children('span').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
$('ul.texts').fadeOut(600, function() {
counter++;
$(this).empty();
doWorkWhenAllFinished(counter);
});
$('.buttonsDiv').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
$('.processingDiv').fadeOut(600, function() {
counter++;
$(this).remove();
doWorkWhenAllFinished(counter);
});
}
Related
I inherited this modal/overlay/content close/empty method that works, but abruptly:
method.close = function () {
$modal.hide();
$overlay.hide();
$content.empty();
$(window).unbind('resize.modal');
};
To fade out gradually, I modified the method like below, but elements are left behind and subsequent clicks don't open new modals loaded with content, only the overlay:
method.close = function () {
$modal.fadeOut('slow', function() {
$(this).hide();
});
$overlay.fadeOut('slow', function() {
$(this).hide();
});
$content.fadeOut('slow', function() {
$(this).empty();
});
$(window).unbind('resize.modal');
};
What am I missing?
UPDATE: The solution is a single nested callback, based on garryp's answer, like this:
method.close = function() {
$overlay.fadeOut('slow', function() {
$overlay.hide();
$content.empty();
});
$modal.hide();
$(window).unbind('resize.modal');
};
Hide is asynchronous; the calls you have in your original code do not block while the transition occurs, execution moves immediately to the next. You need to use callbacks, like this:
var me = $(this); //Added to ensure correct this context
$modal.fadeOut('slow', function () {
me.hide(function () {
$overlay.fadeOut('slow', function () {
me.hide(function () {
$content.fadeOut('slow', function () {
me.empty();
});
});
});
});
});
Assuming the rest of your code is correct this should ensure the transitions fire one after the next.
Firstly, you do not need $(this).hide(). JQuery fadeOut automatically set display: none at the end of fading animation (read more: http://api.jquery.com/fadeout/).
That mean, in your case $content element will also have display: none after fadeOut animation. I expect you forgot to add $content.show() in modal open method.
I'm not sure what to search for exactly but here is my issue.
<script>
function Gbox () {
var hide = document.getElementById('g-box').style.display = "none";
}
Gbox();
$("#g-plus").mouseover(function () {
$("#g-box").show(400);
});
$("#g-plus").mouseleave(function () {
$("#g-box").hide(400);
});
</script>
Said Jquery works without a problem.
Only issue is that if i hover in and out fast 2 times on #g-plus the Jquery runs it 4 times as in show,hide,show,hide and it looks retarded when it happens
How can i avoid this issue?
$("#g-plus").hover(function () {
$("#g-box").show(400);
},function () {
$("#g-box").hide(400);
});
What you need is .stop() to stop the previous animation
function Gbox() {
$("#g-box").hide();
}
Gbox();
$("#g-plus").hover(function () {
$("#g-box").stop().show(400);
}, function () {
$("#g-box").stop().hide(400);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="g-plus">g-plus</button>
<div id="g-box">g-box</div>
Note: You can use .hover() as a short cut to register the mouseenter and mouseleave handlers
Here's my jsfiddle. The script itself is here:
$(function () {
$(".div1, .div2").hide();
$(".link1, .link2").bind("click", function () {
$(".div1, .div2").hide();
if ($(this).attr("class") == "link1")
{
$(".div1").show();
}
else
{
$(".div2").show();
}
});
});
How can I add smooth fadein effect when one div disappears and the other one shows up? Thanks!
$(".div1").fadeIn();
$(".div2").fadeOut();
Running example:
$(function () {
$(".div1, .div2").hide();
$(".link1, .link2").bind("click", function () {
var e = $(this);
$(".div1, .div2").fadeOut().promise().done(function() {
if (e.attr("class") == "link1"){
$(".div1").fadeIn();
} else {
$(".div2").fadeIn();
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
Link 1
Link 2
<div class="div1">I'm div1</div>
<div class="div2">I'm div2</div>
The promise() is used to avoid the collision between fadeOut and fadeIn transitions
It looks like you need the fadeIn() method from jQuery, as explained in the docs:
The .fadeIn() method animates the opacity of the matched elements. It is similar to the .fadeTo() method but that method does not unhide the element and can specify the final opacity level.
if ($(this).attr("class") == "link1") {
$( "#div1" ).fadeIn( "slow", function() {
// Animation complete
});
} else {
$( "#div2" ).fadeIn( "slow", function() {
// Animation complete
});
}
Instead of slow you can also use a number for indicating the fade-in time, in milliseconds.
updated your fiddle.
simply replace show() with fadeIn()
http://jsfiddle.net/cEJtA/572/
QUESTION
How can I prevent a jquery toggle function from running before the previous toggle animation is complete?
I have a simple script to show or hide data depending whether a checkbox is checked.
JQUERY
$('.a').hide();
$('#CB').change(function () {
if ($(this).is(':checked')) {
$('.b').fadeOut(100, function () {
$('.a').fadeIn();
});
} else {
$('.a').fadeOut(100, function () {
$('.b').fadeIn();
});
}
});
PROBLEM
When the event is fired consecutively both elements, in this case .a and .b become visible together. I assume this is because the previous request is not completed prior to firing the function again.
CLICK FOR DEMO
http://jsfiddle.net/keypaul/PbS33/5/
$('.a').hide();
$('#CB').change(function () {
if ($(this).is(":checked")) {
$('.b').stop().fadeOut(100, function () {
$('.a').stop().fadeIn();
});
} else {
$('.a').stop().fadeOut(100, function () {
$('.b').stop().fadeIn();
});
}
});
Using jquery stop()
http://api.jquery.com/stop/
You're right. Animations in jQuery work asynchronously so they could sometimes run at the same time.
To answer your question, I think you already answered it in your question title.
Use a queue.
Set up a flag, name it something like isFading, and when it's true when $("#CB") changes, you queue it instead.
var isFading=false;
var animationQueue = [];
$('#CB').change(function () {
if(isFading){
if ($(this).is(':checked')) {
animationQueue.push(fadeOutFadeIn);
}
else {
animationQueue.push(fadeInFadeOut);
}
}
else{
if ($(this).is(':checked')) {
fadeOutFadeIn();
} else {
fadeInFadeOut();
}
}
);
function fadeOutFadeIn(){
isFading=true;
//insert your fadeout fadein code here
isFading=false;
if(animationQueue.length > 0)
//you're now calling the queued animation to go through
animationQueue.splice(0,1)();
}
function fadeInFadeOut(){
isFading=true;
//insert your fadein fadeout code here
isFading=false;
if(animationQueue.length > 0)
//you're now calling the queued animation to go through
animationQueue.splice(0,1)();
}
Javascript
$(document).ready(function() {
$(".container").animate({left:'120px'}, 6000).queue(function(next){
$(".child").css('display', 'none');
});
});
The above script animates a box and then hides it after the animation is completed.
The problem is that I have a set of identical boxes, and I want to animate each of them. I am trying to use .each to get it to work but so far it doesnt work at all.
So to highlight my question once more*I want to animate a set of identical boxes one after the other in chronological order (html-vise, the one on top first, then the next), and then hide the box setting the css property and value. This works for one box, but not for several. I tried using .each, but no good news there.*
HTML
<div class="container">
<div class="child"></div>
<div class="child"></div>
</div>
function queue(start)
{
var rest = [].splice.call(arguments, 1),
promise = $.Deferred();
if (start)
{
$.when(start()).then(function () {
queue.apply(window, rest);
});
} else {
promise.resolve();
}
return promise;
}
function animate()
{
queue(function () {
return $( ".child:first" ).animate({opacity: "show"}, "slow").delay(1500);
}, function () {
return $( ".child:first" ).animate({opacity: "hide"}, "slow");
}, function () {
return $( ".child:second" ).animate({opacity: "show"}, "slow").delay(1500);
}, function () {
return $( ".child:second" ).animate({opacity: "hide"}, "slow");
}});
}
call animate when you want to fade in and out your divs
You can also do it this way !
<script>
$(document).ready(function() {
$(".container").animate({left:'120px'}, 6000).queue(function(next){
var childs = $('.child'),
i = 0;
(function() {
$(childs[i++]).hide('slow',arguments.callee);
})();
});
});
</script>
Hope this can help you