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
Related
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);
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 );
}
});
I've searched for how to use setTimeOut with for loops, but there isn't a lot on how to use it with while loops, and I don't see why there should be much difference anyway. I've written a few variations of the following code, but this loop seems to crash the browser:
while(src == '')
{
(function(){
setTimeout(function(){
src = $('#currentImage').val();
$("#img_"+imgIdx).attr('src',src);
}, 500);
});
}
Why?
Basically I have an image created dynamically whose source attribute takes time to load at times, so before I can display it, I need to keep checking whether it's loaded or not, and only when its path is available in $('#currentImage'), then do I display it.
This code worked fine before I used a while loop, and when I directly did
setTimeout(function(){
src = $('#currentImage').val();
$("#img_"+imgIdx).attr('src',src);
}, 3000);
But I don't want to have to make the user wait 3 seconds if the loading might be done faster, hence I put the setTimeOut in a while loop and shorted its interval, so that I only check for the loaded path every half second. What's wrong with that?
The while loop is creating trouble, like jrdn is pointing out. Perhaps you can combine both the setInterval and setTimeout and once the src is filled, clear the interval. I placed some sample code here to help, but am not sure if it completely fits your goal:
var src = '';
var intervalId = window.setInterval(
function () {
if (src == '') {
setTimeout(function () {
//src = $('#currentImage').val();
//$("#img_" + imgIdx).attr('src', src);
src = 'filled';
console.log('Changing source...');
clearInterval(intervalId);
}, 500);
}
console.log('on interval...');
}, 100);
console.log('stopped checking.');
Hope this helps.
The problem is probably that you're not checking every half second.
setTimeout schedules a function to run at a future time, but it doesn't block, it just runs later. So, in your while loop you're scheduling those functions to run just as fast as it can iterate through the while loop, so you're probably creating tons of them.
If you actually want to check every half second, use setInterval without a loop instead.
Thanks everyone - all the suggestions helped. In the end I used setInterval as follows:
var timer;
// code generating dynamic image index and doing ajax, etc
var checker = function() {
var src = $('#currentImage').val();
if(src !== '') {
$('#img_' + imgIdx).attr('src', src);
clearInterval(timer);
}
};
timer = setInterval(checker, 500);
I have the following code:
// After 8 seconds change the slide...
var timeout = setTimeout("changeSlide()", 8000);
$('div.slideshow').mouseover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearTimeout(timeout);
});
$('div.slideshow').mouseleave(function() {
clearTimeout(timeout);
var timeout = setTimeout("changeSlide()", 8000);
});
What I want to happen is make the function changeSlide run EVERY 8 seconds in a loop unless someone hovers the slideshow div. When they remove the cursor then do the timeout again!
However the loop only happens once and the hover doesn't stop the timeout or start it again :/
EDIT:
This loops great but the hover on and off causes the function to run multiple times:
// After 8 seconds change the slide...
var timeout = setInterval(changeSlide, 2000);
$('div.slide').mouseover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearInterval(timeout);
});
$('div.slide').mouseleave(function() {
clearInterval(timeout);
var timeout = setInterval(changeSlide, 2000);
});
You have a couple issues here. First off, when you set a timeout, you need to store the return of that function call into a variable if you potentially want to stop it.
var slide_timer = setTimeout(changeSlide, 8000);
Second, when you call clearTimeout (rather than clearInterval), you need to pass it an argument. What argument? That variable you stored when you called setTimeout
clearTimeout(slide_timer);
Third, when you use setTimeout, it only fires once. setInterval will continue to fire, then you'd use clearInterval to stop it.
There is an issue in timing with using intervals rather than timeouts. The browser treats them subtly differently, and it may be important to your code to know the difference and use the proper method. If you use intervals, since they only fire once, you'll have to re-establish the timeout every time it fires.
var slide_timer = setTimeout(function () {
changeSlide();
var slide_timer = setTimeout(changeSlide, 8000);
}, 8000);
OR
var slide_timer = setTimeout(changeSlide, 8000);
...
function changeSlide() {
... your code ...
var slide_timer = setTimeout(changeSlide, 8000);
}
(I prefer the former method)
And lastly, whether you use timeouts or intervals, don't pass a string to setTimeout, pass a function reference. See the sample code above, or like this:
var slide_timer = setTimeout("changeSlide()", 8000); // <--- DON'T
var slide_timer = setTimeout(changeSlide, 8000); // <--- DO
var slide_timer = setTimeout(function () { // <--- DO
changeSlide() ;
// other script
}, 8000);
Putting it all together:
// After 8 seconds change the slide...
var slide_timer = setTimeout(changeSlide, 8000);
$('div.slideshow').hover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearTimeout(slide_timer);
}, function() {
slide_timer = setInterval(changeSlide, 8000);
});
Documentation
clearTimeout - https://developer.mozilla.org/en/DOM/window.clearTimeout
setTimeout - https://developer.mozilla.org/en/DOM/window.setTimeout
clearInterval - https://developer.mozilla.org/en/DOM/window.clearInterval
setInterval - https://developer.mozilla.org/en/DOM/window.setInterval
SO answer discussing the subtle difference between intervals and timeouts - https://stackoverflow.com/a/7900293/610573
When you specify setTimeout (or setInterval), it returns a value that is then used for clearTimeout and clearInterval. Correct usage is as follows:
var timeout = setTimeout(changeSlide, 8000);
clearTimeout(timeout);
Also note I am using clearTimeout, not clearInterval.
You'll also notice that I did not put quotes around 'changeSlide', and that I dropped the parens. When passing a string to setTimeout, eval() is used. eval() is, in general, recommended to be avoided. So, instead, we pass it the direct reference to the function (without quotes). We do not use parens, because that would actually call changeSlide() right away, instead of deferring execution to setTimeout (and would pass, as an argument to setTimeout, the result of changeSlide())
EDIT: To get it to run continously, you have to call setTimeout again after each changeSlide call. setTimeout runs once. As an alternative, you can use setInterval, which automatically repeats. The one caveat to setInterval is that if the interval is too short and the callback it calls takes a long time to run, you can end up with a bunch of intervals queued up to execute one after another, without delay. An 8 second interval would likely not face this problem.
EDIT 2:
var timeout;
var changeSlide = function(){
// do something to change slides
clearTimeout(timeout);
timeout = setTimeout(changeSlide, 8000);
}
// queue up the first changeSlide, all others happen inside changeSlide
timeout = setTimeout(changeSlide, 8000);
$('div.slideshow').mouseleave(function() {
clearTimeout(timeout);
var timeout = setTimeout(changeSlide, 8000);
});
I think you need setInterval and not setTimeout, since:
setTimeout(expression, timeout); runs the code/function once after the timeout
setInterval(expression, timeout); runs the code/function in intervals, with the length of the timeout between them
In the end this worked the best (but I won't accept this as my answer as it was others who helped me get to this point)
// After 8 seconds change the slide...
var slide_timer = setInterval(changeSlide, 2000);
$('div.slideshow').hover(function() {
// If the user hovers the slideshow then reset the setTimeout
clearInterval(slide_timer);
}, function() {
slide_timer = setInterval(changeSlide, 2000);
});
Your issue may be the mouseover event. The mouseover event bubbles, so if you have a nested HTML structure, then the event may be called more than once. If you are using jQuery, you should use the mousenter event, which will only get called once for the element.
On a different note, instead of using setInterval use a setTimeout pattern. Something like this:
//Immediately Invoked Function Expression that gets called immediately
(function() {
//Make the initial call to your setTimeout function
repeat();
//Function will constantly be called
function repeat() {
setTimeout(function() {
//(Put your conditional logic here)
console.log('test');
repeat();
}, 2000);
}
})();
I'm basically trying to accomplish the following. I want it so 5 seconds after the page loads, it'll set the variable to true.
Once true, it'll proceed to give the alert "true".. for now. If someone tries to click the button before 5 seconds, it'll give the alert false.
You've got the right idea, but you have a minor issue with variable scope. To reduce headaches, it's really best to get away from using the string eval option on setTimeout (which is shown in tutorials all around the web, I know) and use an anonymous function:
var link;
function loading(){
setTimeout(function(){
link = true;
}, 5000);
}
This way, you'll know exactly where link is declared and the scope is crystal clear.
Try this:
setTimeout(function() { window.link = true; }, 5000);
This will set the global variable "link" to true after 5 seconds, which will satisfy your if statement.
Edit
This may be a bit complicated if you're a beginner, but a better way to accomplish this is to use function-scope rather than global scope.
In your case, declare the timer function like this:
var timer = (function () {
var link = false;
setTimeout(function() { link = true; }, 5000);
return function() {
alert(link);
};
}());
This way, the anonymous function returns another function which becomes timer(), but this way timer has access to its "private" link variable. For more information, check out Mozilla's article on JavaScript variable scope
Simple one-liner timeout:
setTimeout(() => alert("Time is up!"), 1000);
You can obviously execute any code within:
let seconds = 5;
let timer = setInterval(() => console.log(`${seconds--} seconds left`), 1000);
setTimeout(() => {
clearInterval(timer);
console.log('💥')
}, 5999);