How to kill a looping function in jquery - javascript

I created a function that iterates over a set of divs, looping, fading in and out the next one.
What I am trying to do is to stop it upon either 'click', if/else, or focus. In doing some searching, it seems that I can utilize the setTimeout - clearTimeout functions. However I am a bit unclear on how to go about it, and maybe implementing it incorrectly.
Fiddle Me This Batman
HTML:
Kill Loop Function
<div id="productBox">
<h3>Dynamic Title Here</h3>
<div class="divProduct">
<!-- product image -->
<div class="product-discription">
<h4>Product 1</h4>
<p>Cras justo odio, dapibus ac facilisis in.</p>
Learn More
</div>
</div>
<!-- Repeat '.divProduct' over and over -->
</div>
JS:
timer = null;
function productTypeCycle(element) {
timer = setTimeout(function() {
element.fadeIn()
.delay(1000)
.fadeOut(function() {
if(element.next().length > 0) {
productTypeCycle(element.next());
}
else {
productTypeCycle(element.siblings(":nth-child(2)"));
}
});
}, 500);
}
$(document).ready(function() {
productTypeCycle($(".divProduct:first"));
$(".killFunc").click(function(e) {
e.preventDefault();
if(timer !== null) {
clearTimeout(timer);
}
});
});
Of course, as usual, I am probably way over thinking something that could be so simple.

the problem here is that you stop your timer correctly, but sadly your timer has internally via jQuery started another "timer" for the animations.
you would need to stop the animation instead of the timer:
var animationEle = null;
function productTypeCycle(element) {
animationEle = element;
element.fadeIn()
.delay(1000)
.fadeOut(function () {
if (element.next().length > 0) {
productTypeCycle(element.next());
} else {
productTypeCycle(element.siblings(":nth-child(2)"));
}
});
}
$(document).ready(function () {
productTypeCycle($(".divProduct:first"));
$(".killFunc").click(function (e) {
e.preventDefault();
if (animationEle)
$(animationEle).stop(true, false);
});
});
working fiddle

Another (cleaner) way to go about it, is to let the last animation finish, but set a value to stop any further animations.
http://jsfiddle.net/hhwfq/54/
Like this.
timer = null;
var animationCancelled = false;
function productTypeCycle(element) {
timer = setTimeout(function() {
element.fadeIn()
.delay(1000)
.fadeOut(function() {
if(animationCancelled) return;
if(element.next().length > 0 ) {
productTypeCycle(element.next());
}
else {
productTypeCycle(element.siblings(":nth-child(2)"));
}
});
}, 500);
}
$(document).ready(function() {
productTypeCycle($(".divProduct:first"));
$(".killFunc").click(function(e) {
e.preventDefault();
if(timer !== null) {
clearTimeout(timer);
animationCancelled = true;
}
});
});

The issue is the fade, not the timer. The fade is still executing. You need to run $(element).stop(); on all the elements that have started an animation otherwise they'll just continue.

Related

Stop a recursive function

I am completely new in javascript and jquery... I have searched but can not find an answer to my problem...
I need to stop a function that call itself at the end (I read that this is called recursive function)
So my html
<div id="slide_show"></div>
Stop
My js
//call effect on load
$(function() {
moveSlide(true);
});
//move the div
function moveSlide(repeat) {
if(repeat === true) {
$('#slide_show').slideToggle('slow',function() {
setTimeout(function() {
moveSlide(true);
},2000);
});
} else {
return;
}
}
//stop the function
$(document).on('click','.stop',function(e) {
e.preventDefault();
moveSlide(false);
});
The function is called forever but I want to stop the function of being repeated when I click the button
What am I doing wrong?
Try with: clearTimeout() in else condition .
You need to create the setTimeout() in one variable.Then apply the clearTimout() if the condition is false(Its means a else statement)
var timer;
//call effect on load
$(function() {
moveSlide(true);
});
//move the div
function moveSlide(repeat) {
if(repeat === true) {
console.log('running')
$('#slide_show').slideToggle('slow',function() {
timer = setTimeout(function() {
moveSlide(true);
},2000);
});
} else {
clearTimeout(timer);
console.log('stopped')
return;
}
}
//stop the function
$(document).on('click','.stop',function(e) {
e.preventDefault();
moveSlide(false);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div id="slide_show"></div>
Stop
I see that you are calling ever time at the method moveSlide, into the setTimeout
$('#slide_show').slideToggle('slow',function() {
setTimeout(function() {
**///moveSlide(true); ///here , will be calling recursive untill end**
},2000);
});
Test and tell us, if will help it
tks

during scroll call a function only once

I have a counter on a page. When I scroll to it I need start it only once. but now it starts twice during next scroll. Thank's.
var quit = false;
$(window).scroll(function() {
// ...
something();
function something() {
if (quit == true) {
return;
}
quit = true;
setTimeout(function() {
$(begin).html(2002);
}, 500); // this function must be call only once
}
}
}
$(document).on('scroll', function() {
something();
$(document).off('scroll');
});
this solution helped me https://github.com/HubSpot/odometer/issues/35
my second mistake was creating "new odometer" object

Start/stop function with setInterval

i've got a simple setInterval function for radio buttons to loop on load.
I would like to add a button, which could start or stop the loop. I've added click function for the function, but don't know how to stop it afterwards.
Here is what i've got so far: jsfiddle
Also, if i click the button more times in a row, loop goes berserker - any help appricieted :)
p.s. I've also checked:
start & stop / pause setInterval with javascript, jQuery and
Javascript loop-problem with setTimeout/setInterval
but i was wondering in the dark on how to use those answers as i'm javascript noob.
Make a reference to your setInterval so you can use clearInterval(yourreference).
To start / stop, you can add an extra boolean variable to toggle start and stop.
var t;
var running = false;
$("#start-stop").click(function(){
clearInterval(t);
running = !running;
if (!running)
return;
t = setInterval(function(){
$('.wrap input')
.eq( ( $('input:checked').index() + 1 ) % 3 )
.prop('checked',true);
},1000);
});
Fiddle
Try
jQuery(function () {
var timer;
$("#start-stop").click(function () {
if (timer) {
clearInterval(timer);
timer = undefined;
} else {
timer = setInterval(function () {
$('.wrap input')
.eq(($('input:checked').index() + 1) % 3)
.prop('checked', true);
}, 1000);
}
});
})
Demo: Fiddle
le solution without clearInterval
jQuery(function () {
var toggle = null;
$("#start-stop").click(function () {
if(toggle == null) {
toggle = false;
setInterval(function () {
if(toggle)
$('.wrap input').eq(($('input:checked').index() + 1) % 3).prop('checked', true);
}, 1000);
}
toggle = !toggle;
});
});
Fiddle HERE

The bounce effect in jquery is not working ideally

I want create element which will appear with bounce effect and this effect should run all time while user not clicking to help_man, when its happened effect is completed. Now its work, but not prefer, effect run slow and eventually faster and faster. Bounce does not always stop on mouse click event.
JsFiddle
HTML:
<div class='task_wrapper'>
<div class='help_man'>
<img src='images/cow.png'/>
</div>
</div>
JS:
<script src="js/jquery-ui-bounce.min.js"></script>
<script>
var to_stop = 0;
function run_bounce()
{
if(to_stop==0)
{
$(".task_wrapper").effect( "bounce", "fast" );
setInterval(run_bounce,3000);
}else{
return;
}
}
$(document).ready(function(){
$(".help_man").click(function() {
to_stop = 1;
});
run_bounce();
});
</script>
Thanks!
You need to add positon as abosulte in CSS.That is way we animate DOM elements on fly.
Alway best pratices to clearInterval before call setInterVal(); which return number.
.task_wrapper{
postion:absolute;
}
var to_stop = 0,interval;
function run_bounce()
{
if(to_stop==0)
{
$(".task_wrapper").effect( "bounce", "fast" );
clearInterval(interval);
interval = setInterval(run_bounce,3000);
setInterval(run_bounce,3000);
}else{
$(".task_wrapper").stop(); //Note here stop()
}
}
$(document).ready(function(){
$(".help_man").click(function() {
to_stop = 1;
});
run_bounce();
});
Fiddle Demo
I think you need to clear the interval,
Fiddle: http://jsfiddle.net/9nEne/13/
JS
var to_stop = 0, interval;
function run_bounce() {
if(to_stop==0)
{
$(".task_wrapper").effect( "bounce", "fast" );
clearInterval(interval);
console.log(interval);
interval = setInterval(run_bounce,3000);
}else{
$(".task_wrapper").stop();
}
}
$(document).ready(function(){
$(".help_man").click(function() {
to_stop = 1;
});
run_bounce();
});

Button hiding not functioning properly

HTML Code:
<div id="slick-slidetoggle">wxyz</div>
<div id="slickbox" >abcd</div>​
JavaScript:
var hoverVariable=false;
var hoverVariable2=false;
$('#slickbox').hide();
$('#slick-slidetoggle').mouseover(function() {
hoverVariable2=true;
$('#slickbox').slideToggle(600);
return false;
})
$('#slick-slidetoggle').mouseleave(function() {
hoverVariable2=false;
setTimeout(function (){
if(!hoverVariable && !hoverVariable2){
$('#slickbox').slideToggle(600);
return false;}
}, 1000);
})
$('#slickbox').mouseleave(function() {
hoverVariable=false;
setTimeout(function (){
if(!hoverVariable && !hoverVariable2){
$('#slickbox').slideToggle(600);
return false;}
return false;
}, 1000);
})
$('#slickbox').mouseover(function() {
hoverVariable2=false;
hoverVariable=true;
})​
CSS Code:
#slickbox {
background: black;
width:100px;
height: 135px;
display: none;
cursor:pointer;
color:white;
}
#slick-slidetoggle{
background: yellow;
width:100px;
height: 135px;
cursor:pointer;
color:black;
}
​
Now the desired behaviour is that when mouse is slide over yellow div("wxyz") black div("abcd") should slide down and if mouse is moved out of yellow without moving on to black div, the black div should hide after two seconds.
This is happening. If mouse is moved over black div immediately after moving out of yellow div the black div should not hide as long as the mouse is on the black div. This is also happening.
Next steps are bit difficult to explain but I'll try, when mouse is moved over yellow div and black div comes out then mouse is moved over black div and within two seconds if it moved out of it(black div) then the whole animation goes haywire. Its behaviour is reversed. But if the mouse is kept on black div for more than two seconds and then it is moved out then the whole script runs fine.
This is the link to explain better. http://jsfiddle.net/HAQyK/381/
Try replacing slideToggle() with the appropriate slideUp() and slideDown() calls. http://jsfiddle.net/tppiotrowski/HAQyK/386/
var hoverVariable = false;
var hoverVariable2 = false;
$('#slickbox').hide();
$('#slick-slidetoggle').mouseover(function() {
hoverVariable2 = true;
$('#slickbox').slideDown(600);
return false;
})
$('#slick-slidetoggle').mouseleave(function() {
hoverVariable2 = false;
setTimeout(function() {
if (!hoverVariable && !hoverVariable2) {
$('#slickbox').slideUp(600);
return false;
}
}, 1000);
})
$('#slickbox').mouseleave(function() {
hoverVariable = false;
setTimeout(function() {
if (!hoverVariable && !hoverVariable2) {
$('#slickbox').slideUp(600);
return false;
}
return false;
}, 1000);
})
$('#slickbox').mouseover(function() {
hoverVariable2 = false;
hoverVariable = true;
})​
I re-coded a solution. Checkout the fiddle here
var hideB;
var $black = $('#slickbox');
var $yellow = $('#slick-slidetoggle');
function showBlack() {
if( hideB ) window.clearTimeout( hideB );
$black.stop( true, true );
$black.slideDown(600);
}
function hideBlack() {
hideB = setTimeout( function( ) {
$black.stop( true, true );
$black.slideUp( 600 ); }
, 1000 );
}
$black.hide();
$yellow.mouseenter(function() {
showBlack();
})
$yellow.mouseleave(function() {
hideBlack();
});
$black.mouseleave( function( ) {
hideBlack();
});
$black.mouseenter( function( ) {
showBlack();
});
Your problem seems to be that the slideToggle in firing twice in quick succession because of your duplicate timeout functions. The cleanest way to deal with timeouts or intervals is to store them in a variable to give you the control of removing them when not needed:
// Defined in global scope
var timer;
$('#slick-slidetoggle').mouseleave(function() {
hoverVariable2=false;
// Timer set as function
timer = setTimeout(function (){
if(!hoverVariable && !hoverVariable2){
$('#slickbox').slideToggle(600);
// Timer no longer need and so cleared
clearTimeout(timer);
return false;}
}, 1000);
});
EDIT: Neglected to add the slideUp/slideDown instead of Toggle as per the correct answer above. See the updated jsFiddle which is now correct: http://jsfiddle.net/HAQyK/390/
Another way you could approach your script is to use jQuerys delay funciton and the stop(); method for animation. Wrap the divs in a container and you've got a much simpler block of code:
$('#slick-container').mouseenter(function() {
$('#slickbox').stop().slideDown(600);
}).mouseleave(function(){
$('#slickbox').stop().delay(1000).slideUp(600);
});
Check it out here: http://jsfiddle.net/HAQyK/387/

Categories