jQuery function loop don't stop after checkbox unchecked - javascript

I have a checkbox, which starts a loop of a function called "next". So far that work's correctly. Unckecked box should stop the function loop. That doesn't work. I found in the stackoverflow-forum, that it is necessary to declare a variable of the Interval-ID outside the if-else-statement. No success. Any ideas?
This is the code:
$('input[type="checkbox"]').click(function(){
var intervalID = 0;
if($(this).is(":checked")){
var intervalID = setInterval(next, 400);
}
else if($(this).is(":not(:checked)")){
clearInterval(intervalID);
}
}
);
Regards

"I found in the stackoverflow-forum, that it is necessary to declare a variable of the Interval-ID outside the if-else-statement"
There's a lot more to scopes than that. In your case, when you initialise a variable inside the function, it is only available inside that function. I would highly recommend reading up on scopes, there's a lot of good information out there that doesn't need to be repeated here. For example: http://www.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
You really need to run through your code to understand what's happening. Look at the code and think about it. Every time a checkbox is clicked, you are setting intervalID to 0. So it's not at all surprising that the clearInterval function isn't working.
You need to store that variable outside of the entire click function, so it's accessible the next time the event is fired. Also, else will suffice. There's only 2 possible options; if the first check returns false then you know it isn't checked - you don't need to test it.
var intervalID = 0;
$('input[type="checkbox"]').click(function(){
if ( $(this).is(":checked") ) {
intervalID = setInterval( next, 400 );
}
else {
clearInterval( intervalID );
}
});

Related

Javascript fire the last event

I'm coding a web application and I don't know how to keep on what I'm trying to do with Javascript.
I have a function that is fired when I do zoom on a map or when I move the map. I try to avoid this function do its stuff until it's been a while (2 seconds, for example). Ok, I can use a setInterval method to achieve it.
But what I want and I don't know how to do is... if I do zoom 3 times, very close in time between them, I just want to process the last zoom, not the two previuos ones. I mean, the 2 first function callings have to be cancelled, or something like that.
How could I do that?
Example (pseudo-code) of what I have:
function doStuff() {
setInterval(function({
// do some stuff here...
}, 2000);
}
myMap.on('dragend', doStuff); // If I move inside the map
myMap.on('zoomend', doStuff); // If I do zoom on the map
What I´d try is to set capture the intervalID in a global varial everytime you start your interval; then when you fire the event you check if the variable is set, if it is, you use the clearInterval function to cancel the previous interval before starting the next one.
Something like this:
var intervalID = 0;
function doStuff(){
if(intervalID != 0){
window.clearInterval(intervalID);
}
intervalID = setInterval(function({
// do some stuff here...
intervalID = 0; // try reseting the intevalID on completion, not sure if here
}, 2000);
// Your stuff
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval
You could use a object.addEventListener('load', function())-function.
The function inside it will fire after the object has loaded.

Setting variables using timer in JS

trying to figure out how to do this and I'm not too sure. I'm trying to update local GPS coordinates every 3 seconds using setTimeout and it's not working properly. I'm very new to js so any help is appreciated. This is what I have so far-
In my main JS file, I have this...
var lat_in={};
var long_in={};
var alt_in={};
$.getScript("test_points.js", function(){
console.log("TP script go");
});
$("#Initiate").click(function() {
if (coordinate=="GPS")
{
console.log("GPS go");
lat_out = lat_in;
long_out = long_in;
alt_out = alt_in;
console.log(lat_out, long_out, alt_out)
}
)}
I'm calling the lat/long/alt from another js document (test_points.js), where the setTimeout is...
setTimeout(function(){
var lat_in=5;
var long_in=5;
var alt_in=-5;
}, 3000);
I have a bunch of setTimeouts one after another, and what I'm trying to do is update the variables every 3 seconds and run them through the if statement again.
Am I even close to doing this properly? Thanks in advance
You have declared those variables with a "var" keyword which makes them local to the function passed to the timeout function. Please remove var and try again.
EDIT :
As other have pointed out, you should use interval instead of timeout and once the changes are reflected, then only you should try accessing them.
JavaScript has two kind of timers, one provides a timeout (delayed execution of a piece of code) called window.setTimeout (because setTimeout is a method of the window object) and a timer that runs a piece of code after a certain interval called window.setInterval.
Watch how both work
setTimeout(function(){
document.getElementById("showcase").innerHTML += "setTimeout fired only once after 3 seconds. <br />"}, 3000);
setInterval(function(){
document.getElementById("showcase").innerHTML += "setInterval fired every after 5 seconds. <br />"}, 5000);
//not part of the solution, just to demonstrate.
setInterval(function(){
document.getElementById("timer").textContent = 1 + parseInt(document.getElementById("timer").textContent);
}, 1000)
#showcase {
padding: 4px;
border: 1px solid grey;
background-color: #f3f3f3;
}
<span id="timer">0</span> seconds <br />
<div id="showcase"></div>
To let a timer run multiple times use setInterval.
On your case
setTimeout(function(){
var lat_in=5;
var long_in=5;
var alt_in=-5;
}, 3000);
When you replace setTimeout to setInterval it still won't work. As others commented, you are declaring the lat_in etc. inside the scope of the function. This means that the variables inside that function are only accessibele inside the function bound to the interval. The keyword is var. It tells the parser to "bind" the variables to the scope of the function. Leave the var and your timer function will overwrite the global variables declared outside the function. The sample below should be fine.
setInterval(function(){
lat_in=5;
long_in=5;
alt_in=-5;
}, 3000);
Also when you first declared the variables they are declared as an empty object.
var lat_in={};
var long_in={};
var alt_in={};
using {} is the same as doing lat_in = new Object(). However in your function you overwrite them with integers. Maybe this isn't meant to be. Check the documentation on your GPS coding to what input it needs.
While we are at it:
you can stop timers too with window.clearTimeout and window.clearInterval. Each referring to its own function of course.
To do this, you need to store the timer into a variable:
timer = window.SetInterval(function(){ ... }, 3000); //always in milliseconds.
clearInterval(timer); // this line will now clear the timer.
Also a smart person could remark: "I can let setTimeout behave like an interval."
window.setTimeout(myTimerFunction, 3000);
function myTimerFunction(){
//do stuff here
window.setTimeout(myTimerFunction, 3000); //call itself again in three seconds.
}
Since setTime out is asynchronous you should not start expressions like lat_out = lat_in; before initialising.
And also you are declaring the variables using Var which makes them local.so remove var.
Simply use setInterval function to call a function after an interval continuesly
$("#Initiate").click(function() {
var intervalCall = window.setInterval(myCallback, 3000);
)}
function myCallback(){
if (coordinate=="GPS")
{
console.log("GPS go");
lat_out = lat_in;
long_out = long_in;
alt_out = alt_in;
console.log(lat_out, long_out, alt_out)
}
}
For more information about setInterval, you can read here

stopping a nested javascript function running more than once

I'm trying to get a javascript function to run only once. I've seen this question has been asked before, e.g. Function in javascript that can be called only once, but I can't get the solutions in here to work. I'm not sure if it's because I've got nested functions, or whether there's something I'm missing. Essentially, I'm trying to run a function which, when a webpage is scrolled, it:
- runs a little animation on a canvas in the header
- reduces the size of the header
- leaves it at that
But when there is any subsequent scrolling, the animation keeps re-running. Here's a summarised version of the non-working code:
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
},1000);
}
});
I've also tried declaring a global variable, setting it to "false" in a "window.onload" function, then set it to true in an if function that runs the animation (the if function running only if the variable is false), but that doesn't stop it either. Thoughts?
What you're looking for is something along the lines of listenToOnce where the listener fires the one time, but never again. This could be modified to a number of calls, but the logic is like so:
Register the listener.
Then once the listener fires, remove it.
See .off
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
// $(document).off('scroll'); // or here
},1000);
}
$(document).off('scroll'); // remove listener, you can place this in the setTimeout if you wish to make sure that the classes are added/removed
});
Don't use a time out. That is why you are getting in trouble. Declare a variable outside of your function using var, that will make it global. Your code should be inside of a check for that variable. Before executing your code the first time but inside of the check, change that variable so that the code will never run again.
Try avoid setTimeout. Almost all animation can be watched for end.
function doHeaderAnimation() {
return $('header').animate();
}
function makeHeaderSmall() {
$("header").removeClass("large").addClass("small");
}
function handleScroll(event) {
if ($(document).scrollTop() > 0) {
doHeaderAnimation().then(makeHeaderSmall);
$(document).off("scroll", handleScroll);
}
}
$(document).on("scroll", handleScroll);

jQuery while object.hasClass

I'm trying to find a way to stop a function at a certain point until something does not have a specific class anymore. I cannot change the place where this class is being assigned and removed because it's a plugin.
I was thinking of doing something like this
function DoSomething() {
while ($('div.divControl').hasClass('playing'))
{
//Wait here
}
};
Is this the correct way to go?
This will block so the element will never be changed, as no other code will execute.
What you need to use is an interval:
var interval = setInterval(DoSomething, 500);
function DoSomething() {
if ($('div.divControl').hasClass('playing'))
{
// Do something
clearInterval(interval);
}
};
This will execute the function every half second. The interval will be cancelled after the function succeeds.
No, that will just hang the browser as it goes into an infinite loop.
Your best bet (as best I can think at the moment anyhow) is to do a setTimeout on the function and have it check to see if it your div still has the class every quarter of a second or so.
Still, not nice at all =[

Watching setTimeout loops so that only one is running at a time

I'm creating a content rotator in jQuery. 5 items total. Item 1 fades in, pauses 10 seconds, fades out, then item 2 fades in. Repeat.
Simple enough. Using setTimeout I can call a set of functions that create a loop and will repeat the process indefinitely.
I now want to add the ability to interrupt this rotator at any time by clicking on a navigation element to jump directly to one of the content items.
I originally started going down the path of pinging a variable constantly (say every half second) that would check to see if a navigation element was clicked and, if so, abandon the loop, then restart the loop based on the item that was clicked.
The challenge I ran into was how to actually ping a variable via a timer. The solution is to dive into JavaScript closures...which are a little over my head but definitely something I need to delve into more.
However, in the process of that, I came up with an alternative option that actually seems to be better performance-wise (theoretically, at least). I have a sample running here:
http://jsbin.com/uxupi/14
(It's using console.log so have fireBug running)
Sample script:
$(document).ready(function(){
var loopCount = 0;
$('p#hello').click(function(){
loopCount++;
doThatThing(loopCount);
})
function doThatOtherThing(currentLoopCount) {
console.log('doThatOtherThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatThing(currentLoopCount)},5000)
}
}
function doThatThing(currentLoopCount) {
console.log('doThatThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatOtherThing(currentLoopCount)},5000);
}
}
})
The logic being that every click of the trigger element will kick off the loop passing into itself a variable equal to the current value of the global variable. That variable gets passed back and forth between the functions in the loop.
Each click of the trigger also increments the global variable so that subsequent calls of the loop have a unique local variable.
Then, within the loop, before the next step of each loop is called, it checks to see if the variable it has still matches the global variable. If not, it knows that a new loop has already been activated so it just ends the existing loop.
Thoughts on this? Valid solution? Better options? Caveats? Dangers?
UPDATE:
I'm using John's suggestion below via the clearTimeout option.
However, I can't quite get it to work. The logic is as such:
var slideNumber = 0;
var timeout = null;
function startLoop(slideNumber) {
//... code is here to do stuff here to set up the slide based on slideNumber...
slideFadeIn()
}
function continueCheck() {
if (timeout != null) {
// cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
return false;
} else {
return true;
}
};
function slideFadeIn() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
$mySlide.fadeIn(fade, function() {
timeout = setTimeout(slideFadeOut,display);
});
}
};
function slideFadeOut() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
slideNumber=slideNumber+1;
$mySlide.fadeOut(fade, function() {
//... code is here to check if I'm on the last slide and reset to #1...
timeout = setTimeout(function(){startLoop(slideNumber)},100);
});
}
};
startLoop(slideNumber);
The above kicks of the looping.
I then have navigation items that, when clicked, I want the above loop to stop, then restart with a new beginning slide:
$(myNav).click(function(){
clearTimeout(timeout);
timeout = null;
startLoop(thisItem);
})
If I comment out 'startLoop...' from the click event, it, indeed, stops the initial loop. However, if I leave that last line in, it doesn't actually stop the initial loop. Why? What happens is that both loops seem to run in parallel for a period.
So, when I click my navigation, clearTimeout is called, which clears it.
What you should do is save the handle returned by setTimeout and clear it with clearTimeout to interrupt the rotator.
var timeout = null;
function doThatThing() {
/* Do that thing. */
// Schedule next call.
timeout = setTimeout(doThatOtherThing, 5000);
}
function doThatOtherThing() {
/* Do that other thing. */
// Schedule next call.
timeout = setTimeout(doThatThing, 5000);
}
function interruptThings() {
if (timeout != null) {
// Never mind, cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
}
}
When a navigation element is clicked simply call interruptThings(). The nice part is that it will take effect immediately and you don't need to do any polling or anything else complicated.

Categories