JavaScript: clearInterval won't clear interval - javascript

I have an unusual problem. I'm using the following script to check for internet connection using navigator.onLine. If there is internet connection, the page will be refreshed every 15 seconds. If there isn't any internet connection, the page will use innerHTML to display a message.
<script type="text/javascript">
setInterval(function () {
if (navigator.onLine) {
var myInterval = setInterval(function(){window.location.href = "Tracker.html";},15000);
} else {
clearInterval(myInterval);
var changeMe = document.getElementById("change");
change.innerHTML = "<big><font face='Arial' color='#ffffff' size='2'><center>OFFLINE</big><br>No internet connection</font></center>";
}
}, 250);
</script>
My problem is, once there is no internet connection, the message will be displayed, BUT the page would still be refreshed one last time. I'm trying to avoid this, by using clearInterval(myInterval); in the else part of the code, however it won't work.
Any suggestions?

To refresh the page at 15 second intervals (provided that a connection is present), use:
function refresh() {
if(navigator.onLine)
window.location.href = "Tracker.html";
else{
var changeMe = document.getElementById("change");
change.innerHTML = "<big><font face='Arial' color='#ffffff' size='2'><center>OFFLINE</big><br>No internet connection</font></center>";
setTimeout(refresh, 250);
}
}
setTimeout(refresh, 15000);
At the end of 15 seconds, this checks whether a connection is present. If there is, it refreshes the page. If there isn't, it proceeds to check every 250 milliseconds afterwards until the user is reconnected, at which point it refreshes the page.
The net result is that the script refreshes the page as soon as possible after a minimum of 15 seconds have elapsed.
Here is a demonstration: http://jsfiddle.net/JGEt9/show

Whenever the outer interval callback is executed, a new myInterval variable is created and the previous one is lost (it goes out of scope because the callback terminates).
You have to persist the value of the variable between function calls by declaring it outside of the function. You also have to make sure that you are not creating another timeout if one is already running.
var timeout = null;
setInterval(function () {
if (navigator.onLine) {
if (timeout === null) {
timeout = setInterval(function(){window.location.href = "Tracker.html";},15000);
}
} else {
clearTimeout(timeout);
timeout = null;
// ...
}
}, 250);

You need to declare myInterval outside of the if statement. You should only need the refresh code once too. Something like this:
var myInterval = setTimeout(function(){window.location.href = "Tracker.html";},15000);
setInterval(function () {
if (!navigator.onLine) {
clearTimeout(myInterval);
var changeMe = document.getElementById("change");
changeMe.innerHTML = "<big><font face='Arial' color='#ffffff' size='2'><center>OFFLINE</big><br>No internet connection</font></center>";
}
}, 250);
Here you set the refresh interval and continually check to see if the browser is offline, and if it is, you remove the timer and do your cleanup code. I also changed the refresh code to use setTimeout instead of interval because it only happens once.
Another issue is you create changeMe but then try to use change. change doesn't exist. I fixed that in my example as well.
Note: This will not resume refreshing once connection is regained. See Felix Kling's answer.

Related

Adding an event listener to stop a timer started from another function jQuery

Sorry this is going to take a bit of explaining so you know what I'm trying to do here...
I'm having trouble with a timer function. Basically when the user hits the page, an Ajax request is made, the result of which starts a timer function. They have a certain amount of time in which to make a payment (this is a block chain based payment app, payment is made via an external wallet - no user input is required on the payment page at all, no buttons to click etc). If the timer runs out the payment box resets.
But if the persistent Ajax calls running in the background find the users payment on the block chain I need to kill the timer as it is no longer required, but I need to keep the payment box open while the confirmations are being monitored until the transaction is complete.
The trouble is I can't alter the already running timer function. I've tried every way possible I could think of but nothing stops the original function from running and ultimately resetting the payment box while the transaction is ongoing (waiting for confirmations).
I have been reading about wrapping the timer function in an object and adding a listener but everything I found seemed really confusing to me.
Below is the relevant code.
The function that starts the timer is being started by the Ajax response from another function...
myTimer(expiry);
The expiry variable being passed is vital as it sets an intial on / off state for the timer (whether to display it or not from the first response). So I need to keep that.
This is the timer function...
function myTimer(expiry) {
// If expiry set to 0 don't use the timer
if (expiry === 0) {
$('#timer').hide();
return;
}
var start = new Date();
var timeoutVal = Math.floor(expiry/100);
animateUpdate();
function updateProgress(percentage) {
$('#timerInner').css("width", percentage + "%");
}
function animateUpdate() {
var now = new Date();
var timeDiff = now.getTime() - start.getTime();
var perc = Math.round((timeDiff/expiry)*100);
if (perc <= 100) {
updateProgress(perc);
setTimeout(animateUpdate, timeoutVal);
} else {
// Timer expired, clear box and show buy button again
$("#paymentWrap").empty();
$("#btn-Pay").show();
$("#btn-Pay").prop("disabled", false);
return;
}
}
}
}
This is the part that I need to "kill" on demand via another function coming from another Ajax response...
// Timer expired, clear box and show buy button again
$("#paymentWrap").empty();
$("#btn-Pay").show();
$("#btn-Pay").prop("disabled", false);
return;
Can somebody explain how I can add a variable listener to this function (maybe by creating it as an object?) so that I can change the chunk of code that triggers the bit above to include a new var called cancelled that can be updated elsewhere in the script WHILE this function is running.
if (perc <= 100) {
updateProgress(perc);
setTimeout(animateUpdate, timeoutVal);
if (cancelled === true) {
// Hide the timer div and kill the timer function
$("#timer").hide();
return;
}
} else {
// Timer expired, clear box and show buy button again
.......
I know this was really long winded, apologies upfront, but thanks for reading and looking forward to any help you can offer.
Cheers!
You can define a global variable to reference setTimeout() call and use cleaTimeout()
let timer = null;
let then_ = new Date().getTime() + 10000;
function fn() {
timer = setTimeout(function() {
console.log("doing stuff at " + new Date()
, "time remaining to do stuff:", then_ - new Date().getTime());
if (new Date().getTime() < then_) {
fn()
} else {
done()
}
}, 1000)
}
function done() {
clearTimeout(timer);
timer = null;
console.log("done doing stuff at " + new Date());
}
document.querySelector("button")
.onclick = function() {
if (timer) {
done()
} else {
this.onclick = null;
}
}
fn();
<button>clear timer</button>

Measure time spent by a user during a website visit

I'm trying to build a website locally using PHP and Javascript and MAMP.
What I'm looking for is to put a timer on every page of the website and that timer counts the time spent by the user in the whole website. Even if the user switches between pages the timer will still continue. The solution I've found only shows the time spent on each page and when I reload the same page again the timer restart from zero.
Here's the Javascript for the timer I did:
window.onload=function(){
time=0;
}
window.onbeforeunload=function(){
timeSite = new Date()-time;
window.localStorage['timeSite']=timeSite;
}
I've search everywhere for the solution but with no luck, if anyone knows how to do this please let me know.
Here's a working example. It will stop counting when the user closes the window/tab.
var timer;
var timerStart;
var timeSpentOnSite = getTimeSpentOnSite();
function getTimeSpentOnSite(){
timeSpentOnSite = parseInt(localStorage.getItem('timeSpentOnSite'));
timeSpentOnSite = isNaN(timeSpentOnSite) ? 0 : timeSpentOnSite;
return timeSpentOnSite;
}
function startCounting(){
timerStart = Date.now();
timer = setInterval(function(){
timeSpentOnSite = getTimeSpentOnSite()+(Date.now()-timerStart);
localStorage.setItem('timeSpentOnSite',timeSpentOnSite);
timerStart = parseInt(Date.now());
// Convert to seconds
console.log(parseInt(timeSpentOnSite/1000));
},1000);
}
startCounting();
Add the code below if you want to stop the timer when the window/tab is inactive:
var stopCountingWhenWindowIsInactive = true;
if( stopCountingWhenWindowIsInactive ){
if( typeof document.hidden !== "undefined" ){
var hidden = "hidden",
visibilityChange = "visibilitychange",
visibilityState = "visibilityState";
}else if ( typeof document.msHidden !== "undefined" ){
var hidden = "msHidden",
visibilityChange = "msvisibilitychange",
visibilityState = "msVisibilityState";
}
var documentIsHidden = document[hidden];
document.addEventListener(visibilityChange, function() {
if(documentIsHidden != document[hidden]) {
if( document[hidden] ){
// Window is inactive
clearInterval(timer);
}else{
// Window is active
startCounting();
}
documentIsHidden = document[hidden];
}
});
}
JSFiddle
Using localStorage may not be the best choice for what you need. But sessionStorage, and localStorage is most suitable. Have in mind that sessionStorage when opening a new tab resolves to a new session, so using localStorage has to do with the fact that if only sessionStorage was used and a user opened a new tab in parallel and visit your website would resolve to a new separate session for that browser tab and would count timeOnSite from start for it. In the following example it is tried for this to be avoid and count the exact timeOnSite.
The sessionStorage property allows you to access a session Storage
object for the current origin. sessionStorage is similar to
Window.localStorage, the only difference is while data stored in
localStorage has no expiration set, data stored in sessionStorage gets
cleared when the page session ends. A page session lasts for as long
as the browser is open and survives over page reloads and restores.
Opening a page in a new tab or window will cause a new session to be
initiated, which differs from how session cookies work.
function myTimer() {
if(!sessionStorage.getItem('firstVisitTime')) {
var myDate = Date.now();
if(!localStorage.getItem('timeOnSite')) {
sessionStorage.setItem('firstVisitTime',myDate);
} else {
if(localStorage.getItem('tabsCount') && parseInt(localStorage.getItem('tabsCount'))>1){
sessionStorage.setItem('firstVisitTime',myDate-parseInt(localStorage.getItem('timeOnSite')));
} else {
sessionStorage.setItem('firstVisitTime',myDate);
}
}
}
var myInterval = setInterval(function(){
var time = Date.now()-parseInt(sessionStorage.getItem('firstVisitTime'));
localStorage.setItem('timeOnSite',time);
document.getElementById("output").innerHTML = (time/1000)+' seconds have passed since first visit';
}, 1000);
return myInterval;
}
window.onbeforeunload=function() {
console.log('Document onbeforeunload state.');
clearInterval(timer);
};
window.onunload=function() {
var time = Date.now();
localStorage.setItem('timeLeftSite',time);
localStorage.setItem("tabsCount",parseInt(localStorage.getItem("tabsCount"))-1);
console.log('Document onunload state.');
};
if (document.readyState == "complete") {
if(localStorage.getItem("tabsCount")){
localStorage.setItem("tabsCount",parseInt(localStorage.getItem("tabsCount"))+1);
var timer = myTimer();
} else {
localStorage.setItem("tabsCount",1);
}
console.log("Document complete state.");
}
Working fiddle
If you want a server-side solution then set a $_SESSION['timeOnSite'] variable and update accordingly on each page navigation.

Redirect with inactivity

My objective is to keep a user in a view as long as he/she keeps clicking a button within a certain lapse.
I'm using Rails and was exploring a solution via an embedded JS in the pertinent view.
So far I'm able to set a time after which the user will be redirected to root path with the following script:
var delayedRedirect = function (){
window.location = "/";
}
var delay = 10000;
$(document).ready(function() {
setTimeout('delayedRedirect()', delay);
});
I've been trying to write a function that resets the value of 'delay'or that calls the setTimeoutFunction again.
$('#btn-persist').click(function() {
delay = 3000;
// or calling again setTimeout('delayedRedirect()', delay);
});
But I noticed that changing the variable won't affect the setTimeout function that has already been called.
I've also tried to use the clearTimeout function as below without success
var delayedRedirect = function (){
window.location = "/persists";
}
var delay = 3000;
var triggerRedirect = function() { setTimeout('delayedRedirect()', delay);
}
var stopRedirect = function (){
clearTimeout(triggerRedirect);
}
$(document).ready(function() {
triggerRedirect();
$('#btn-persist').click(function() {
stopRedirect();
});
});
I wonder why this may not be working and if there's any other way to stop the execution of the setTimeout function that has already been called so I can call it again to effectively reset the time to the original value of 'delay'.
At the same time, I don't want to stop any other JS functions that are running in parallel.
Do you see a better solution to achieve this?
The main problem why clearTimeout is not working. because you are clearing a anonymous function instead of a setTimeout variable
change this
var triggerRedirect = function() { setTimeout('delayedRedirect()', delay);
}
to this
var triggerRedirect = setTimeout('delayedRedirect()', delay);
Edit:
also change this (if you want to restart the inactive redirect trigger)
$('#btn-persist').click(function() {
stopRedirect();
});
to this
$('#btn-persist').click(function() {
stopRedirect();
triggerRedirect();
});

Run setTimeout only when tab is active

Is there a way to stop setTimeout("myfunction()",10000); from counting up when the page isn't active. For instance,
A user arrives at a "some page" and stays there for 2000ms
User goes to another tab, leaves "some page" open.
myfunction() doesn't fire until they've come back for another 8000ms.
(function() {
var time = 10000,
delta = 100,
tid;
tid = setInterval(function() {
if ( document.hidden ) { return; }
time -= delta;
if ( time <= 0 ) {
clearInterval(tid);
myFunction(); // time passed - do your work
}
}, delta);
})();
Live demo: https://jsbin.com/xaxodaw/quiet
Changelog:
June 9, 2019: I’ve switched to using document.hidden to detect when the page is not visible.
Great answer by Šime Vidas, it helped me with my own coding. For completeness sake I made an example for if you want to use setTimeout instead of setInterval:
(function() {
function myFunction() {
if(window.blurred) {
setTimeout(myFunction, 100);
return;
}
// What you normally want to happen
setTimeout(myFunction, 10000);
};
setTimeout(myFunction, 10000);
window.onblur = function() {window.blurred = true;};
window.onfocus = function() {window.blurred = false;};
})();
You'll see that the window blurred check has a shorter time set than normal, so you can set this depending on how soon you require the rest of the function to be run when the window regains focus.
You can do something like:
$([window, document]).blur(function() {
// Clear timeout here
}).focus(function() {
// start timeout back up here
});
Window is for IE, document is for the rest of the browser world.
I use almost the same approach as Šime Vidas in my slider
but my code is based on document.visibilityState for page visibility checking:
document.addEventListener("visibilitychange", () => {
if ( document.visibilityState === "visible" ) {
slideshow.play();
} else {
slideshow.pause();
}
});
About Page Visibility
API: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
What you'd have to do is set up a mechanism to set timeouts at small intervals, keeping track of total elapsed time. You'd also track "mouseenter" and "mouseleave" on the whole page (the <body> or something). When the short-term timeouts expire, they can check the window state (in or out) and not restart the process when the window is not in focus. The "mouseenter" handler would start all paused timers.
edit — #Šime Vidas has posted an excellent example.
I've finally implemented a variation of #Šime Vidas' answer, because the interval was still running if I opened another program and the browser window was not visible, but the page executing the interval was the active browser tab. So, I've modified the condition to document.hidden || !document.hasFocus(). This way, if the document is hidden or the document doesn't have the focus, the interval function just returns.
(function() {
var time = 10000,
delta = 100,
tid;
tid = setInterval(function() {
if ( document.hidden || !document.hasFocus() ) { return; }
time -= delta;
if ( time <= 0 ) {
clearInterval(tid);
myFunction(); // time passed - do your work
}
}, delta);
})();

Using timers (onload)

Ok, firstly, I hardly know Javascript. I really don't know what I'm doing.
So, I have this code:
var interval_id = 0;
var prevent_bust = 0;
// Event handler to catch execution of the busting script.
window.onbeforeunload = function() { prevent_bust++ };
// Continuously monitor whether busting script has fired.
interval_id = setInterval(function() {
if (prevent_bust > 0) { // Yes: it has fired.
prevent_bust -= 2; // Avoid further action.
// Get a 'No Content' status which keeps us on the same page.
window.top.location = 'http://vadremix.com/204.php';
}
}, 1);
function clear ()
{
clearInterval(interval_id);
}
window.onload="setTimeout(clear (), 1000)";
After 1 second I want to clear the interval set earlier. This isn't working. How would I do what I'm trying to do?
If you substitute the last line with window.onload = function() { setTimeout(clear, 1000); }, it should do OK.
There are two errors in your code:
window.onload should be a function, rather than a string ("..."),
setTimeout accepts a function (clear), rather than the result from the function (clear())
By the way, these are some good places to learn JavaScript:
QuirksMode
Mozilla Developer Network

Categories

Resources