JS clearInterval() will not clear - javascript

Just moments ago I asked a question about why my setInterval() function would only run once,
JS setInterval() only runs once when animating opacity
I had that answered, but then I wanted to check and make sure the loop stopped, so I added an alert() to the loop and found out clearInterval is not clearing even though I initially ran the setInterval function connected to a global variable...
the opacity change works fine, but now the alert box goes on infinitely after you click OK... eventually I won't need the alert function I just wanted to see if the interval actually cleared which it doesn't...
var run;
var runOpt;
document.getElementById('menu-1-A').style.opacity=0;
document.getElementById('menu-1-B').style.opacity=0;
function openSubMenu1(item) {
runOpt=item;
run = setInterval(runSubMenu1,35);
}
function runSubMenu1() {
var i=document.getElementById('menu-1-'+runOpt);
if (parseInt(i.style.opacity) == 1) {
clearInterval(run);
alert('done');
} else {
i.style.opacity = parseFloat(i.style.opacity) + .1;
}
}

Thank you plalx -- openSubMenu1() was run from onmouseover which was repeatedly calling openSubMenu1(), I created a variable to test if the menu is open, if it is openSubMenu1() returns false before calling setInterval()..
now it only runs once. Thanks.

What may be happening is that you are starting multiple instances before the first setInterval has finished, so the clearTimeout has the wrong reference when called.
The following uses closures instead of globals so each call has its own timeout reference:
<div id="d0">jere</div>
<script>
var makeOpaque = (function() {
var timeout, el;
return function(id) {
if (!el) {
el = document.getElementById(id);
timeout = setInterval(makeOpaque, 50)
} else if (el && el.style.opacity < 1) {
el.style.opacity = +el.style.opacity + 0.1;
// debug
console.log(el.id + ' : ' + el.style.opacity);
} else {
timeout && clearInterval(timeout);
alert('done');
}
}
}());
makeOpaque('d0');

Related

endless while loop after mousemove

I am going crazy here.
I want to show an element on mouse move, and hide it 10 sec after last move of the mouse.
I wrote this:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
document.addEventListener("mousemove", function(event) {
console.log('$');
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
<div class='mybar'>
<h1> TESTING </h1>
</div>
Why does it end up in an endless loop?
Why doesn't it exit on condition? why does the if never gets the 'true' parameter?
Notice : don't run it this way... it will kill your tab.
First, you don't need to wait for DOMContentLoaded to add an event listener to document, since if you did, you couldn't add DOMContentLoaded in the first place.
The infinite loop is because setTimeout doesn't pause the script. It schedules its callback for the time you provide, and irrespective of that time, the callbacks will not run until the current running code in the thread completes, which never happens because you don't increment the time variable.
So the loop never ends, and so the thread is never made available, so your callbacks never can run, so time can never be incremented.
Lastly, starting a setTimeout inside an event handler that shares a local variable and executes very rapidly on an event like mousemove is prone to give unexpected results. For example, in your code, every time the handler runs, it'll reset time to 0, which doesn't seem to be what you'd want.
A solution would be to ditch the loop, schedule the visibility for 10 seconds, and prevent the main part of the code in the handler from running in the meantime by using a boolean variable.
var timer = null;
document.addEventListener("mousemove", function(event) {
var myBar = document.querySelector(".mybar");
if (!myBar) {
return; // there's no mybar element
}
if (timer == null) {
myBar.style.visibility = 'visible';
} else {
clearTimeout(timer); // clear the currently running timer
}
// set to hidden in 10 seconds
timer = setTimeout(function() {
myBar.style.visibility = 'hidden';
timer = null; // clear the timer
}, 10000);
});
I also switched to querySelector instead of getElementsByClassName because it's shorter and cleaner. And I used a variable to make sure the element is found before setting the style.
You need a flag out of the mousemove scope that tells your listener that you've already ran.
if(running) return;
running = true;
In context:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
var running = false;
document.addEventListener("mousemove", function(event) {
console.log('$');
if(running) return;
running = true;
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
Here's a way to do it with regular JavaScript. If your browser isnt ES6 compliant, you can replace the arrow functions with regular function expressions. The example hides the text after 2 seconds instead of 10, just so you can see it work without having to waste 8 extra seconds.
//hide by default
document.getElementById('myBar').style.display = 'none';
var timer = null;
var hideDivTimer = () => {
timer = setTimeout(() => {
document.getElementById('myBar').style.display = 'none';
}, 2000);
};
document.addEventListener('mousemove', () => {
clearTimeout(timer);
document.getElementById('myBar').style.display = 'inline';
hideDivTimer();
});
<body>
<div id='myBar'>
<h1> TESTING </h1>
</div>
</body>

fail to create function interval to prevent other function run

hello i try to create the function to prevent the other function to run for 10 minutes IF user close the content and refresh the page.
the other function is to show the content when we scroll with 2 argument
first: it will run the function with first argument with no interval, if user click close and refresh. it will run the second argument that give interval
heres my code.
https://jsfiddle.net/8c1ng49a/1/
please look this code
var popUp= document.getElementById("popup");
var closePopUp= document.getElementsByClassName('popup-close');
var halfScreen= document.body.offsetHeight/2;
var showOnce = true;
var delay;
function slideUp(){
popUp.style.maxHeight="400px";
popUp.style.padding="10px 20px";
popUp.style.opacity="1";
if(popUp.className==="closed"){
popUp.className="";
}
}
function slideDown(){
popUp.style.maxHeight="0";
popUp.style.padding="0 20px";
popUp.style.opacity="0";
// add class closed for cache
if(popUp.className===""){
popUp.className="closed";
localStorage.setItem('closed', 'true'); //store state in localStorage
}
}
// start interval
function startDelay() {
delay = setInterval(slideUp, 1000);
}
// clear interval
function clearDelay() {
window.clearTimeout(delay);
}
// check if cache heve class close
window.onload = function() {
var closed = localStorage.getItem('closed');
if(closed === 'true'){
popUp.className="closed";
}
}
// show popup when scroll 50%
window.onscroll = function scroll(ev) {
// first time visited
if ((window.innerHeight+window.scrollY) >= halfScreen && showOnce) {
slideUp();
showOnce = false;
}
//same user mutilple time visited the site
else if((popUp.className==="closed" && window.innerHeight+window.scrollY) >= halfScreen && showOnce ){
startDelay();
showOnce = false;
}
};
// close button when click close
for(var i = 0; i<closePopUp.length; i++){
closePopUp[i].addEventListener('click', function(event) {
slideDown();
});
}
my interval didnt work onthe second argument its fire when i refresh, i dont know why.
but if add startDelay on my first arguments its work. but i need to place the interval on my second argu
When you want to make delay use setTimeout function.
Here is documentation of this function.
setInterval Repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.

Execute after cleartimeout function finished (jQuery)

I have this istuation. I have a setTimeout to a function in which I fade out and fade in an element. In a few seconds this timeout is cleared with cleartimeout and right after is called .hide() to hide this element. The problem is that sometimes it doesnt hide the element. I have a feeling it has something to do with timing.
Example:
function first_func(){
$('.element').fadeOut(function(){
// Do other stuff like change element's position
$('.element').fadeIn();
});
interval1 = setTimeout(function(){first_func()},500);
}
function second_func(){
countdown--;
if (countdown<0){
last_func();
}
interval2 = setTimeout(function(){second_func()},1000);
}
function begin_func(){
first_func();
second_func();
}
function last_func(){
clearTimeout(interval1);
clearTimeout(interval2);
$('.element').hide();
}
So basically the problem is that in last_func I clear both intervals and HIDE the element, but sometimes the element is still visible on the page. So I am guessing that it does hide but the interval is still in progress and it fades back in.
If anyone would have some suggestion please
Just a suggestion, but this bit appears wrong to me:
function second_func(){
countdown--;
if (countdown<0){
end_func();
}
interval2 = setTimeout(function(){second_func()},1000);
}
Even if you're calling end_func() to stop everything, you're setting a new timeout after that.
function second_func(){
countdown--;
if (countdown<0){
end_func();
} else {
interval2 = setTimeout(second_func, 1000);
}
}
Another hint: To avoid that running fadeIn/fadeOuts affect the hiding of the element, you should clear the animation queue:
$('.element').stop(true, true).hide();
By default fadeIn and fadeOut use duration of 400 milliseconds, u can change it by set first parameter.
$('.element').fadeOut( [duration] [, callback] );
You seem to never call last_func, is end_func() supposed to be last_func()?
This works:
http://jsfiddle.net/CZ9hr/1/
May I suggest a simpler approach for what you seem to want to achieve: http://jsfiddle.net/fSEjR/2/
var countdown = 3,
$element = $('.element');
for (var i = 0; i < countdown; i++) {
$element.fadeOut().fadeIn(function() {
countdown--;
if (countdown === 0) $element.hide();
});
};
This works because animations are automatically queued in jquery.

setInterval and clearInterval not working as expected

I have this function which acts as a loading box using setInterval to change the background images which creates a flashing effect.
function loading() {
clearInterval(start);
var i = 0;
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
var start = setInterval(function() {
boxes();
}, 350);
}
But even with clearInterval if I click on it more than once the flashing goes out of order. I tried removing the boxes, hiding them but I can't seem to get the 'buffer' cleared? Any ideas?
The reason why it keeps flashing is because every time loading gets called it creates a new variable start, so clearInterval is actually doing nothing. You also shouldn't have the boxes function within loading because it is doing the same thing, creating a new boxes function every time loading is called. This will add a lot of lag the longer the script executes.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(function() {
boxes();
}, 350);
}
function boxes() {
var in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
Function declarations get "hoisted" to the top of their scope, this is what is messing the execution order. Check this: http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
The reason is every time you call loading it creates a new Interval or new var start. So if you click it twice, then you have two things manipulating the same data. So you need to have the var start outside of the function and the clearInterval inside. So every time you call loading it clears the interval and creates a new one.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(boxes, 350);
}
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
maybe you should take a look at this Jquery Plugin , it seems to manage intervals very well .
Jquery Timers Plugin

window.clearInterval is not working?

I'm using JS to animate two images by having them toggle on and off. I have an initial image which, when the animation is turned on, appears on the screen and stays on. The second image, which has a higher z value, is then set to toggle on and off every 1 second in the same location as the first image, so it appears as if the two are alternating.
I'm using window.setInterval to make the second image blink, but when I need to turn the animation off (and I'm removing both images from the screen), my window.clearInterval is not "working" The first image will be gone, but the second one keeps blinking on and off every second.
Code:
function notebookNotification(setting)
{
$("#lightNotificationContainer").show();
var notificationAnimation = window.setInterval('$("#darkNotificationContainer").toggle()', 1000);
if(setting == 0)
{
window.clearInterval(notificationAnimation);
$("#lightNotificationContainer").hide();
$("#darkNotificationContainer").hide();
}
}
Anyone see why it isn't working?
Reading between the lines, I think what you're saying is this:
You execute notebookNotification(1); and the animation starts
You execute notebookNotification(0); and the animation does not stop.
My guess is that you want notebookNotification(0) to disable the flashing.
In order to do that, you need to rework this function considerably. You need to store the intervalID that comes from setInterval in a variable that survives outside of the scope of this function and can be used for clearInterval on subsequent calls to this function.
For example:
var intervalID;
function notebookNotification(setting)
{
if(setting == 0)
{
if(intervalID) {
window.clearInterval(intervalID);
intervalID = null;
}
$("#lightNotificationContainer").hide();
$("#darkNotificationContainer").hide();
}
else
{
$("#lightNotificationContainer").show();
if(!intervalID) {
intervalID = window.setInterval('$("#darkNotificationContainer").toggle()', 1000);
}
}
}
Here, try this:
http://jsfiddle.net/WGxmy/
Saving the interval to a global variable -- not one inside a function -- lets you clear it later.
var keepflashing = true;
var isShowing = true;
function notebookNotification()
{
if(!isShowing)
$("#lightNotificationContainer").show();
else
$("#lightNotificationContainer").show();
isShowing = !isShowing;
if(keepflashing)
setTimeout( function(){ notebookNotification(setting); },100);
else
{
$("#lightNotificationContainer").hide();
$("#darkNotificationContainer").hide();
}
}
Maybe you can avoid calling clearInterval() generally?
function notebookNotification(setting)
{
if(setting == 0)
{
$("#lightNotificationContainer").hide();
$("#darkNotificationContainer").hide();
}
else
{
$("#lightNotificationContainer").show();
window.setInterval('$("#darkNotificationContainer").toggle()', 1000);
}
}

Categories

Resources