Avoid javascript's variables reset when user uses back and foward - javascript

Well,
I Have a countdown timer, and I'm facing the following problem:
My countdown starts at 90 seconds. If the user waits until it reaches 2 seconds, for example, then he goes back using browser's button and after goes forward (backing to the same page), the countdown restarts at 90 seconds, not at 2 as I need, because when the timer reaches 0 I "click" at a button which post the form.
I know I need to handle the back and forward button and set my variable with the new value but I don't have any idea how can I do it. Any help will be great.
My code is below:
var count = 90;
var screenCount = count;
var newCount = 0;
function countFunction() {
if (screenCount != 0) {
var minutes = Math.floor(count / 60);
var seconds = count - minutes * 60;
if (count > 60){
if (seconds < 10)
seconds = "0" + seconds;
screen = minutes + "m:" + seconds + "s";
$('.timer').css('width',"120px")
}
else{
if (count < 10)
screen = "0" + count;
else
screen = count + "s";
$('.timer').css('width',"60px")
}
document.getElementById('tempo').innerHTML = screen;
if (count == 0) {
set('temporizador', screenCount);
$(":submit").removeAttr("disabled");
$('#responder').click();
}
if (count != 0) {
set('temporizador',screenCount - count );
count = count - 1;
setTimeout("countFunction()", 1000);
}
}
else {
document.getElementById('tempo').innerHTML = '∞';
set('temporizador', newCount);
newCount++;
setTimeout("countFunction()", 1000);
}
}

When the user presses back a whole new page is loaded, with an entirely new Javascript context. If you want to pass information from the context of one page to the context of another, there are several ways to do it.
In your particular situation, using LocalStorage is the easiest:
// count down 90 seconds, including page navigation on this site
var count = +localStorage.getItem('timerCount') || 90;
function countDown() {
count--;
localStorage.setItem('timerCount', count);
if (count<0) window.clearInterval(myInterval);
}
var myInterval = window.setInterval(countDown, 1000);
Suggestion by #DmitryVolokh
In this example i stored the remaining time in localStorage. If you want to track the elapsed time from a particular moment, you would be better served to store the starting time instead and compute the difference.

You use local storage for this as suggested above but there is the slight issue that some older browsers don't support localStorage: http://caniuse.com/#search=local%20storage
Since you are only storing a single number you could also use a cookie:
var match, count;
if (match = /timerCount=(\d+);/.exec(document.cookie)) {
count = match[1];
} else {
count = 90
}
function countDown() {
count--;
document.cookie = 'timerCount=' + count + ';';
if (count<0) window.clearInterval(myInterval);
}
var myInterval = window.setInterval(countDown, 1000);

You can use the onbeforeunload javascript event to see when the users leave the page, and then act as you want : changing the window.location to redirect the user (and give additional parameters like your timer), or prevent him from leaving the page.
You can also create a cookie or use localstorage to store the timer and get it back next time user comes to your page.

Related

How to get seconds to countdown properly after button click event

To start, I am brand new to Javascript so please excuse my naivete.
I am working on a countdown timer to start on a button click. The timer does start on the click, however, the seconds timer immediately changes (minus 1) and then after that proceeds to countdown every second (as desired).
for example: timer is at 25:00.
button is clicked, timer immediately drops to 24:59 (without a second passing)
then proceeds to countdown as normal.
Thank you in advance.
let min = 25;
let sec = 60;
let remainSec = sec % 1;
let minText = document.getElementById('minutes');
minText.innerText = min; //declared outside of sample
let secondsText = document.getElementById('seconds');
secondsText.innerText = remainSec + '0' ; //declared outside of sample
startTime.addEventListener('click', decrement); //declared outside of sample
function decrement() {
sec--;
secondsText.innerText = sec;
if (sec < 10){
secondsText.innerText = '0' + sec;
}
setInterval(decrement, 1000);
}
You can use a timeout:
startTime.addEventListener('click', function() { setTimeout(decrement,1000) });
You don't need the setInterval inside the decrement function, this way it will be called multiple times, and the decrement will occur more then once per second.
Do something like this:
startTime.addEventListener('click', decrement); //declared outside of sample
let interval;
function startDecrement() {
if (!interval) { // avoid duplicate interval
interval = setInterval(decrement, 1000);
}
}
function decrement() {
sec--;
secondsText.innerText = sec;
if (sec < 10){
secondsText.innerText = '0' + sec;
}
}
Another cool stuff is that storing the interval allows you cancelling it using the [clearInterval()](
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval) function.
function stopDecrement() {
clearInterval(interval);
interval = null;
}
Additional information
The if statement that checks if a interval was already declared works because javascript any value in a Truthy or Falsy value when using with ! (NOT operator). See Understanding JavaScript Truthy and Falsy
So, when you call setInterval() it returns an unique non-zero integer that identifies the interval, allowing you to cancel it in the future.
On the first run, the interval variable is empty because we just declared it without a value.
let interval;
console.log(interval); // undefined
console.log(!interval); // true
interval = setInterval(decrement, 1000);
console.log(interval); // 1
console.log(!interval); // false

prevent user from refreshing a page multiple times

I am facing a issue when a user holds F5 for 10-15 minutes the web page becomes unresponsive and finally IIS throws an error.
To manage this, I want to restrict the user from pressing F5(lock F5 event) after certain number of times. After some time interval say 5 minutes I want to enable the refresh functionality(unlock F5 event).
I am using a cookie to save the number of times user presses F5. To handle cookie I am using the code mentioned here.
Assign a event to check if F5 keypress.
$(document).on("keydown", tryingF5);
I am using a variable to hold the cookie value and incrementing it once user presses F5.
var numberOfF5Click = 1;
var thresholdClick = 10;
var numberOfF5Click = 1;
function tryingF5(e) {
if ((e.which || e.keyCode) == 116) {
//alert(numberOfF5Click);
if (numberOfF5Click > thresholdClick) {
e.preventDefault();
alert("Multiple refresh has been prevented for some time!!");
}
numberOfF5Click = numberOfF5Click + 1;
docCookies.setItem("NumberOfF5Click", numberOfF5Click);
//alert("F5 Clicked =" + numberOfF5Click);
};
};
The complete code is setup here : JSBin
Question: The code is not working as expected, something is n and How could I do it better ?
Try this:
var everyXMinutes = 5 * 1000; // 5 seconds
var maxPerEveryXMinutes = 5; // 5 times per x seconds.
document.onkeydown = function (e) {
if (e.keyCode === 116) {
if (!localStorage.refreshments) {
localStorage.refreshments = JSON.stringify([]);
}
var refreshments = JSON.parse(localStorage.refreshments);
var date = new Date();
if (date.getTime() - refreshments[refreshments.length - 1] >= everyXMinutes) {
refreshments = [];
} else if (refreshments.length >= maxPerEveryXMinutes) {
alert("You must wait " + ((everyXMinutes - (date.getTime() - refreshments[refreshments.length - 1])) / 1000) + "s in order to be able to use the refresh function.");
return false;
}
refreshments.push(date.getTime());
localStorage.refreshments = JSON.stringify(refreshments);
}
};

setTimeout executes faster than simultaneous setInterval

So, I have a setInterval and a setTimeout running simultaneously in this click-o-meter thing I'm doing: the user enters an specified number of seconds he/she wants the game to run for, and then it counts how many clicks you have done, what was the average time between each click, and the average amount of clicks per second you've made during the specified period of time.
<html>
<head></head>
<body>
<input type='text' id='timerInput'></input>
<button id='btn'>Click</button>
<script>
var before;
var now;
var clicks = 0;
var cts = 0; //Stands for 'Clicks This Second'
var intervals = new Array();
var cps = new Array();
var cpsCounter;
var timer;
var canContinue = true;
var timerInput = document.getElementById('timerInput');
var timerTime;
var wasBad = false;
document.getElementById('btn').onclick = function() {
if(canContinue) {
if(clicks <= 0) {
if(timerInput.value.replace(/\D/, '') === timerInput.value) {
wasBad = false;
timerTime = parseInt(timerInput.value.replace(/\D/, '')) * 1000;
before = new Date();
cpsCounter = window.setInterval(ctsFunction, 1000);
timer = window.setTimeout(finish, timerTime);
}else{
alert('Only numbers please!');
wasBad = true;
}
}else{
now = new Date();
console.log(now - before);
intervals.push(now - before);
before = new Date();
}
if(!wasBad){
clicks++;
cts++;
}
}else{console.log('Game ended');}
};
function ctsFunction() {
console.log('Clicks this second: ' + cts);
cps.push(cts);
cts = 0;
}
function finish() {
console.log('Clicks: ' + clicks);
console.log('Average Speed (ms): ' + Math.floor(intervals.reduce(function(a, b){return a + b;}) / (clicks - 1)));
console.log('Average Speed (clicks per second): ' + (cps.reduce(function(a, b){return a + b;}) / cps.length));
intervals = new Array();
console.log('cps.length: ' + cps.length);
cps = new Array();
clicks = 0;
cts = 0;
window.clearInterval(cpsCounter);
canContinue = false;
}
</script>
</body>
</html>
So, the problem is that when the gmae finishes, that is, when timer reaches the end, ctsFunction() is supposed to run once more at the last second, so it can register data from it; but finish() is executed faster, or prior to ctsFunction(), thus clearing the cpsCounter interval and not allowing it to do anything on the last second. I've tried adding some extra milliseconds to timer, but if you choose to run the game for enough seconds, the same problem will eventually happen (e.g. if you add 1ms, the problem will be solved for up to 2 seconds, but not for more).
I have a setInterval and a setTimeout running simultaneously
It will never happens because javascript is a single thread language. There is no matter what is in your code, javascript can't execute two commands simultaneously.
And one more:
timer delay is not guaranteed. JavaScript in a browser executes on a
single thread asynchronous events (such as mouse clicks and timers)
are only run when there’s been an opening in the execution.
Read this article to understand how javascript timers work.

Implementing a timer app in Metro App

I am developing a game in Metro app where there would be an initial timer for the game to run, let's say about 1 minute and 50 seconds and the timer is displaying the current time. if the 1 minute and 50 seconds time is over, the game will be over it will show a message, How would I implement such behaviour?
I would say, you can try this (untested):
remainingTime = 110;
setInterval(function() {
countdownStarted(); // game started
},
milliseconds // game will start in this much time
);
function countdownStarted() {
setInterval(function() {
remainingTime = remainingTime*100;
updateTimeOnScreen(); // after every second
if(remainingTime) countdownStarted();
},
100
);
}
function updateTimeOnScreen() {
if(remainingTime == 0) {
timeUp(); // game over
}
// function continues
}
For more examples, I would suggest you to read this article.
This basically does the trick, though this is the only thing my app does, so your real performance might vary and there are likely other improvements, stylistic and otherwise, you can make:
var timer = setInterval(function () {
var div = document.getElementById('time'); // this is just a div
// the div shows the time like this: "1:20" - 1 minute, 20 seconds
var lastValue = div.innerText.split(':');
var newValue = parseInt(lastValue[0]) * 60 + parseInt(lastValue[1]) + 1;
if (newValue === 110) {
div.innerText = "Game over!";
clearInterval(timer);
} else {
div.innerText = Math.floor(newValue / 60) + ':' + newValue % 60;
}
}, 1000);
For something more robust, check out this article. It looks like it's pretty close to what you want to do.
You can create an object that has a setTimeout and clearTimeout methods set to some user-defined value.
This link can also give you some useful info.

Timer counting faster on second run

I am working on a simple game right now. its almost done except for the timer has a glitch in it and I can't figure out whats doing it. when you push a button, an HTML5 text on the canvas starts to count down from 35 to 0. On the first run it's fine. But if you choose to play again with out refresh the timer starts to countdown faster. here is the code.
var timer = 35;
ctx.fillText("Countdown: " + timer, 320, 32);
function resetReggie(){
reggie.x = canvasWidth / 2;
reggie.y = canvasHeight / 2;
}
//Starts Timer for Timed Game
function timedMsg()
{
resetReggie();
ballsCaught = 0;
timer = 35;
alert('Pick up as many as you can in ' + timer + ' seconds');
countDown();
var t=setTimeout(function() {
var again = confirm("TIMES UP! You Gathered " + ballsCaught + " Balls! Play Again?");
if (again === true){
timedMsg();
resetReggie();
}
if (again === false){
resetReggie();
ballsCaught = 0;
timer = 35;
}
}, timer * 1000);
}
function countDown() {
if (timer != 0){
timer-=1;
setTimeout('countDown()', 1000);
}
}
I think the problem is in the line
}, timer * 1000);
where you have a value that is at most 34 at the time 'timer' is evaluated to set the timeout. Because you initialize it to 35 but then call countDown() which decreases it to 34, then you have a call to confirm() which might let 'timer' decrease even more. As a result the subsequent call to timedMsg() happens a little too soon causing countDown() to be called twice as often. Try the following (I ran it in node) and then change the 4 to 6.
function countDown() {
console.log("Countdown: " + timer, 320, 32);
if (timer != 0) {
timer -= 1;
setTimeout(countDown, 1000);
}
}
function timedMsg() {
timer = 5;
countDown();
var t=setTimeout(function() {
timedMsg();
}, 4 * 1000);
}
timedMsg();
As mentioned in my comment, each time you start a new game, it appears you are decreasing the timeout value. As a result, this reduces the time each time.
Try this:
var timeout = currentTime = 5;
var int = setInterval(function() {
​console.log(currentTime);
currentTime--;
if(currentTime < 0) {
var again = confirm('Play again?');
if(again) {
currentTime = timeout;
}
else {
clearInterval(int);
}
}
}, 1000);​
http://jsfiddle.net/gRoberts/CsyYx/
Look at your console (F12 in Chrome), or update the code to write to the browser to see it working ;)

Categories

Resources