stop executing javascript till full cycle - javascript

I made this script to fadeout and fadein (fadeTo) a div when I hover another div, it's almost working perfect but when I quickly hover in and out the div the script keeps looping until it reaches the times I hovered it.
Is it possible to stop (timeout?) the fadeOut/FadeIn effect till the loop is completed? So it stops repeating with a quick hover in and out but that the script works again when the loop is finished
jsFiddle: (quickly hover in and out the red part a few times, you'll notice the text keeps going)
http://jsfiddle.net/v69Jk/
$(function () {
$('.one').hover(function () {
$('.show').fadeTo(600, 0);
},
function () {
$('.show').fadeTo(600, 1);
});
});

Solution 1: cancel the previous animation:
$(function () {
$('.one').hover(function () {
$('.show').stop().fadeTo(600, 0);
},
function () {
$('.show').stop().fadeTo(600, 1);
});
});
Demo
Solution 2: stop event when the animation is not done yet (as you wanted, but this might not work properly because of the hover function)
$(function () {
$('.one').hover(function () {
if (!$('.show').is(':animated')) {
$('.show').fadeTo(600, 0);
}
},
function () {
if (!$('.show').is(':animated')) {
$('.show').fadeTo(600, 1);
}
});
});
Demo

Related

Jquery tabs changing before fade animation

I've wanted to do smooth transition between tabs (first fadetoggle, then change content, fadetoogle again), but "changing content" part doesn't wait for the animation to finish. I.e. content changes before finishing the animation
$('.catalog__wrapper').fadeToggle('slow', executeTabChange(tab, () => $('.catalog__wrapper').fadeToggle()))
Link to jsfiddle
https://jsfiddle.net/Denchuk10111/cowypes2/34/
Something like this
$(document).ready(function() {
$('ul.catalog__tabs').on('click', 'li:not(.catalog__tab_active)', function() {
const tab = $(this);
$('.catalog__wrapper').fadeOut('slow', () => {
executeTabChange(tab, ()=>{
$('.catalog__wrapper').fadeIn()
});
});
});
function executeTabChange(form, callback) {
form
.addClass('catalog__tab_active').siblings().removeClass('catalog__tab_active')
.closest('body').find('div.catalog__content').removeClass('catalog__content_active')
.eq(form.index()).addClass('catalog__content_active');
callback();
}
})

Multi-element jQuery animation issue

I am trying to loop through an animation selecting multiple elements and moving them as long as the mouse hovers over the parent area. This works well enough, but each time the animation loops through the first element (child) moves faster than the others. ??? JSFiddle Example
HTML:
<div id="menuContent">
<button id="btn1" class="mainButton" left="0"/>
<button id="btn2" class="mainButton" left="0"/>
<button id="btn3" class="mainButton" left="0"/>
</div>
jQuery:
$("#menuContent").hover(function () {
loop();
}
, function () {
stop();
}
);
function stop() {
$(".mainButton").stop();
}
function loop() {
$(".mainButton").stop().animate({ left: "+=20"}, 100, 'linear', function () { loop(); });
}
From the documentation:
complete
A function to call once the animation is complete, called once per matched element.
When you call animate it starts 3 animations. Animation for the first element gets started and finished first. And then its complete gets called and you stop and start all animations, though some of them didn't get completed yet.
Consider this example (Fiddle):
function loop() {
$('.mainButton').stop().animate({
left: '+=1'
}, 1, 'linear', function() {
loop();
});
}
Only one circle will be moving because there is no time gap for others to move.
You can use promises to make it work (Fiddle):
$('#menuContent').hover(function() {
$('.mainButton').data('run', true);
loop();
}, function() {
$('.mainButton').data('run', false);
});
function loop() {
if (!$('.mainButton').data('run')) return;
$('.mainButton').animate({left: '+=10'}, 100, 'linear').promise().done(loop);
}
Danil Speransky is correct. However there is an options argument to the animate function to allow animations to not run in a rigid queue.
`$(".mainButton").animate({ left: "+=20"},{queue: false}, 100, 'linear', function () { loop();});`
Check out the documentation for queue:false here.
You're mileage may vary, but doing these two things seem to help a lot:
First, store the jQuery object for the .mainButton elements:
var $mainButton = $('.mainButton')
Second, Make the left increment more and also increase the delay:
$mainButton.stop().animate(
{ left: "+=1000"},
5000,
'linear',
function() { loop() })
You can toy with the numbers more to see if you get even better performance.
https://jsfiddle.net/wotfLyuo/8/
Your complete handler is called, if the animation for one elements in the jquery collection is finished. So when the first element is finished, you call loop and stop the animation of the other elements. Better use promise and done and save the state of your animation within the collection:
$("#menuContent").hover(function () {
start();
}, function () {
stop();
});
function start() {
$(".mainButton").data('stopped', false);
loop();
}
function stop() {
$(".mainButton").data('stopped', true).stop();
}
function loop() {
var $mainButtons = $(".mainButton").stop();
if(!$mainButtons.data('stopped'))
$mainButtons.animate({ left: "+=20"}, 100, 'linear').promise().done(loop);
}
Here is a working fiddle (https://jsfiddle.net/wotfLyuo/5/)

Why Doesn't Modal FadeOut Slowly?

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.

Load() seems to lose scope after it's been evoked

I have a button that fades in some html file, and then a back button that returns the user to initial view. However this only works once. They are unable to click the button again for a more detailed view.
$('.support').click(function () {
$('.main-view').fadeOut('slow', function () {
// Animation complete.
$('.main-view-wrapper').load('includes/modules/support.html');
});
});
$('.back').click(function () {
$('.return-main').fadeOut('slow', function () {
// Animation complete.
$('.main-view-wrapper').load('includes/modules/main-view.html');
});
});
If .back element is generated dynamically, you should delegate the event:
$('.main-view-wrapper').on('click', '.back', function(){
$('.return-main').fadeOut('slow', function () {
// Animation complete.
$('.main-view-wrapper').load('includes/modules/main-view.html');
});
})
$(document).on('click', '.support', function () {
$('.main-view').fadeOut('slow', function () {
// Animation complete.
$('.main-view-wrapper').load('includes/modules/support.html');
});
});
$(document).on('click', '.back', function(){
$('.return-main').fadeOut('slow', function () {
// Animation complete.
$('.main-view-wrapper').load('includes/modules/main-view.html');
});
})
After you've clicked both buttons, you've faded out both .main-view and .return-main, but you never fade them back in. So nothing will happen on the next click. Do you need to fade them in on click of the opposite button?

jQuery featured content slider w/ animations for each slide

I'm creating a feature content slider using jQuery and I have hit a few snags trying to get rid of the last few bugs. It is inspired by http://kleientertainment.com/ so check it out and you'll see what im going for. Any suggestions on achieving this effect even with totally new code would be helpful!
The idea is a simple div swap, but with custom animations for each slide that fire when it is loaded. It also MUST fade to black in between each transition, whether autoplay or clicked.
lets get to the code and bugs:
$(document).ready(function () {
//START SLIDES HIDDEN
$('.slide').css({
'position': 'absolute',
'display': 'none'
});
//RUN FIRST SLIDE
runSlideShow(1);
animation1_swap();
//AUTOPLAY FUNCTION
function runSlideShow(slideNumber) {
$('#slide' + slideNumber).fadeIn(1000).delay(10000).fadeOut(1000, function () {
if (slideNumber == 4) {
animation1_swap();
runSlideShow(1);
}
if (slideNumber == 3) {
animation4_swap();
runSlideShow(4);
}
if (slideNumber == 2) {
animation3_swap();
runSlideShow(3);
}
if (slideNumber == 1) {
animation2_swap();
runSlideShow(2);
}
});
//NAVIGATION BUTTONS
$('#bullet1').click(function () {
$('.slide:visible').stop(true, true).fadeOut(1000, function () {
animation1_swap();
runSlideShow(1);
});
});
$('#bullet2').click(function () {
$('.slide:visible').stop(true, true).fadeOut(1000, function () {
animation2_swap();
runSlideShow(2);
});
});
$('#bullet3').click(function () {
$('.slide:visible').stop(true, true).fadeOut(1000, function () {
animation3_swap();
runSlideShow(3);
});
});
$('#bullet4').click(function () {
$('.slide:visible').stop(true, true).fadeOut(1000, function () {
animation4_swap();
runSlideShow(4);
});
});
}
});
CSS info: .slide sets the dimensions, and #slideX are the individual background images for each. #bulletX are the nav buttons.
Also, the animationX_swap() are the animations specific to that slide. They live in another file and would have made this post way too long.
The bugs:
Right now, the autoplay function is great, you can watch it all day and not see a hiccup. The trouble comes when the nav buttons are used, particularly #bullet1. If i click #bullet1, then go to 2, then back to 1, the autoplay seems to be sped up as the slide fades out before it is supposed to. I am a total beginner but I made it this far, can anyone help me clean this up and essentially reimagine http://kleientertainment.com/ 's slider?
Just discovered jQuery cycle plugin http://malsup.com/jquery/cycle/ from another post.
I remade my slider with that and it preforms exactly as needed. Good stuff!

Categories