I'm learning JS and I'm stuck...
I want to create a countdown (it's done, my countdown is working) who keep running when the page is reloaded.
I used the sessionStorage to "save" the countdown value and also to check if a sessionStorage exists when the page is loaded.
The problem is, I don't know how keep running the countdown with values saved in the sessionStorage.
Could you please help me?
class Timer {
constructor(secondes, minutes) {
this.secondes = secondes;
this.minutes = minutes;
this.button = document.getElementById("button");
this.counter = document.getElementById("counter");
this.storageCheck();
}
countdown(minutes) {
var seconds = this.secondes;
var mins = this.minutes;
var myCounter = this.counter;
function tick() {
var current_minutes = mins-1;
seconds--;
myCounter.innerHTML = current_minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
var duration = sessionStorage.setItem("timer", myCounter.innerHTML);
if( seconds > 0 ) {
setTimeout(tick, 1000);
} else {
if(mins > 1){
countdown(mins-1);
}
}
}
tick();
}
buttonClick() {
button.addEventListener("click", () => {
this.countdown(this.minutes);
})
}
storageCheck() {
if (sessionStorage.getItem("timer")) {
// keep the countdown running
}
}
}
let newTimer = new Timer(60, 20);
newTimer.buttonClick();
<!DOCTYPE html>
<html>
<head>
<title>Test Countdown</title>
</head>
<body>
<div id="counter"></div>
<button id="button">Run</button>
<script type="text/javascript" src="countdown.js"></script>
</body>
</html>
In constructor before initializing secondes and minutes check if they are in the storage.If they dont exists then only set the this.secondes = secondes and this.minutes = minutes;
constructor(secondes, minutes) {
this.button = document.getElementById("button");
this.counter = document.getElementById("counter");
if(!this.storageCheck()){ //check if seconds are mins are stored in storage
this.secondes = secondes; //if not set mins and sec to value passed in constructor
this.minutes = minutes;
}
else{
this.countdown(this.minutes);
}
}
In storage check function , check if the values are there, if there get the values and set to this.secondes and this.minutes and return true else return false
storageCheck() {
//if both mins and secs exists
if (sessionStorage.getItem("mins") &&sessionStorage.getItem("secs")) {
// keep the countdown running
this.minutes=parseInt(sessionStorage.getItem("mins"));//get min
this.secondes=parseInt(sessionStorage.getItem("secs"));//get secs
return true;
}
else
return false;
}
and in countdown funciton save the values to storage
sessionStorage.setItem("mins",vm.minutes);//set current min
sessionStorage.setItem("secs",vm.secondes);//set current sec
Try running this here :https://jsbin.com/bavexigute/1/edit?html,js,console,output
class Timer {
constructor(secondes, minutes) {
this.button = document.getElementById("button");
this.counter = document.getElementById("counter");
if(!this.storageCheck()){ //check if seconds are mins are stored in storage
this.secondes = secondes; //if not set mins and sec to value passed in constructor
this.minutes = minutes;
}
else{
this.countdown();
}
}
countdown() {
debugger;
var vm=this;
if(!(this.minutes-1<0))
this.minutes--;
let tick= function(){
vm.secondes--
if(vm.secondes==0){
vm.secondes=59;
vm.minutes--;
}
vm.counter.innerHTML = vm.minutes + ":" + (vm.secondes < 10 ? "0" : "") + vm.secondes;
if(vm.minutes == 0 && vm.secondes-1==0){
vm.secondes--;
vm.counter.innerHTML = vm.minutes + ":" + vm.secondes-1;
}
else{
setTimeout(tick,1000);
}
sessionStorage.setItem("mins",vm.minutes);//set current min
sessionStorage.setItem("secs", vm.secondes);//set current sec
}
setTimeout(tick,1000);
}
buttonClick() {
button.addEventListener("click", () => {
this.countdown();
})
}
storageCheck() {
//if both mins and secs exists
if (sessionStorage.getItem("mins") && sessionStorage.getItem("secs")) {
// keep the countdown running
this.minutes=parseInt(sessionStorage.getItem("mins"));//get min
this.secondes=parseInt(sessionStorage.getItem("secs"));//get secs
return true;
}
else
return false;
}
}
let newTimer = new Timer(60, 20);
newTimer.buttonClick();
You could use your storage check function to override the minutes and seconds arguments if it exists.
constructor(mins, secs) {
this.mins = mins
this.secs = secs
this.checkStorage = this.checkStorage.bind(this)
this.checkStorage(mins, secs)
}
checkStorage(mins, secs) {
if(window.storage) { // or whatever
this.secs = window.storage.secs
this.mins = window.storage.mins
}
}
Something along those lines. Basically just have the setStorage function change the values that have been set in the constructor.
You can do a simple trick by doing this
window.onload = function() {
let minutes = sessionStorage.getItem("minutes")
let seconds = sessionStorage.getItem("seconds")
let newTimer = new Timer(seconds, minutes);
};
And in sessionStorage instead of storing the whole innerHtml store minutes and seconds hopefully it will solve your problem
Related
I've made a timer with setInterval():
var seconds = 0, minutes = 0;
var timer = document.querySelector("#timer");
var interval = null;
function beginTimer() {
var interval = setInterval(function(){
timer.innerHTML = minutes + " Minute(s) " + seconds + " Seconds";
seconds++;
if(seconds == 60) {
minutes++;
seconds = 0;
}
else if(minutes == 60) {
return "Out of time!";
}
}, 1000);
}
I've set a button in HTML to reset it, but when I use it to clear the timer, it continues running. This is the function with the clearInterval() in it.
function beginGame() {
cards = shuffle(cards);
for (var n = 0; n < cards.length; n++) {
allCards.innerHTML = "";
[].forEach.call(cards, function(item) {
allCards.appendChild(item);
});
cards[n].classList.remove("match", "open", "disable", "show");
}
//resetting values
moves = 0;
counter.innerHTML = moves;
star1.style.visibility = "visible";
star2.style.visibility = "visible";
star3.style.visibility = "visible";
lemon.style.visibility = "hidden";
seconds = 0;
minutes = 0;
clearInterval(interval);
var timer = document.querySelector("#timer");
timer.innerHTML = "0 Minute(s) 0 Seconds";
}
I've been researching this for a couple of days with no luck... could someone kindly help me understand how to stop the timer from continuing to run after reset is initialized? Thanks.
Because you have var interval inside beginTimer, the interval variable inside beginTimer will always reference the local variable, which is distinct from the outer interval (which is never touched). Once beginTimer ends, the local interval variable will simply be garbage collected. Leave off the var to assign to the outer variable instead:
var interval = null;
function beginTimer() {
interval = setInterval(function(){
var intervalinside the beginTimer() is error.
var seconds = 0, minutes = 0;
var timer = document.querySelector("#timer");
var interval = null;
function beginTimer() {
// var interval = setInterval(function(){
interval = setInterval(function(){
timer.innerHTML = minutes + " Minute(s) " + seconds + " Seconds";
seconds++;
if(seconds == 60) {
minutes++;
seconds = 0;
}
else if(minutes == 60) {
return "Out of time!";
}
}, 1000);
}
You need also to reset the ongoing timer before starting a new one. Please try the following:
var interval;
function beginTimer() {
clearInterval(interval);
interval = setInterval(function(){
...
I am in trouble. I did countdown timer code in java script but when I refresh the page timer is reset so how to fix this problem
Here is my code.
var min = 1;
var sec = 59;
var timer;
var timeon = 0;
function ActivateTimer() {
if (!timeon) {
timeon = 1;
Timer();
}
}
function Timer() {
var _time = min + ":" + sec;
document.getElementById("Label1").innerHTML = _time;
if (_time != "0:0") {
if (sec == 0) {
min = min - 1;
sec = 59;
} else {
sec = sec - 1;
}
timer = setTimeout("Timer()", 1000);
} else {
window.location.href = "page2.html";
}
}
<BODY onload="Timer();">
<div id="Label1"> </div>
</BODY>
This approach uses localStorage and does not Pause or Reset the timer on page refresh.
<p id="demo"></p>
<script>
var time = 30; // This is the time allowed
var saved_countdown = localStorage.getItem('saved_countdown');
if(saved_countdown == null) {
// Set the time we're counting down to using the time allowed
var new_countdown = new Date().getTime() + (time + 2) * 1000;
time = new_countdown;
localStorage.setItem('saved_countdown', new_countdown);
} else {
time = saved_countdown;
}
// Update the count down every 1 second
var x = setInterval(() => {
// Get today's date and time
var now = new Date().getTime();
// Find the distance between now and the allowed time
var distance = time - now;
// Time counter
var counter = Math.floor((distance % (1000 * 60)) / 1000);
// Output the result in an element with id="demo"
document.getElementById("demo").innerHTML = counter + " s";
// If the count down is over, write some text
if (counter <= 0) {
clearInterval(x);
localStorage.removeItem('saved_countdown');
document.getElementById("demo").innerHTML = "EXPIRED";
}
}, 1000);
</script>
Javascript is client-sided. It will reset on reload or any other thing.
A simple solution to your problem might be html5 storage, or session storage.
https://www.w3schools.com/html/html5_webstorage.asp
// Store
localStorage.setItem("lastname", "Smith");
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("lastname");
Hope this helped!
You're looking for window.localStorage. Something like this should work:
<script language="javascript" type="text/javascript">
var min = 1;
var sec = 59;
var timer;
var timeon = 0;
function ActivateTimer() {
//Don't activate if we've elapsed.
if(window.localStorage.getItem('elapsed') != null)
return;
if (!timeon) {
timeon = 1;
Timer();
}
}
function Timer() {
var _time = min + ":" + sec;
document.getElementById("Label1").innerHTML =_time;
if (_time != "0:0") {
if (sec == 0) {
min = min - 1;
sec = 59;
} else {
sec = sec - 1;
}
timer = setTimeout("Timer()", 1000);
}
else {
window.localStorage.setItem('elapsed', true);
window.location.href = "page2.html";
}
}
</script>
I am building an aptitude test with a timer. i want to show a div of time out on countdown finish. and is it possible to show a **Lean Modal Popup ** box on countdown finish. Please help!!!. Heres the code
Javascript
<script language="JavaScript" type="text/javascript">
function CountDownTimer(duration, granularity) {
this.duration = duration;
this.granularity = granularity || 1000;
this.tickFtns = [];
this.running = false;
}
CountDownTimer.prototype.start = function() {
if (this.running) {
return;
}
this.running = true;
var start = Date.now(),
that = this,
diff, obj;
(function timer() {
diff = that.duration - (((Date.now() - start) / 1000) | 0);
if (diff > 0) {
setTimeout(timer, that.granularity);
} else {
diff = 0;
that.running = false;
}
obj = CountDownTimer.parse(diff);
that.tickFtns.forEach(function(ftn) {
ftn.call(this, obj.minutes, obj.seconds);
}, that);
}());
};
CountDownTimer.prototype.onTick = function(ftn) {
if (typeof ftn === 'function') {
this.tickFtns.push(ftn);
}
return this;
};
CountDownTimer.prototype.expired = function() {
return !this.running;
};
CountDownTimer.parse = function(seconds) {
return {
'minutes': (seconds / 60) | 0,
'seconds': (seconds % 60) | 0
};
};
window.onload = function () {
var display = document.querySelector('#time'),
timer = new CountDownTimer(5),
timeObj = CountDownTimer.parse(5);
format(timeObj.minutes, timeObj.seconds);
timer.onTick(format);
document.querySelector('button').addEventListener('click', function () {
timer.start();
});
function format(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ':' + seconds;
}
if(display.textContent == 0){
document.querySelector("#div1").style.display="block";
}
};
</script>
Html
<button>Start Count Down</button>
<div>Registration closes in <span id="time"></span> minutes!</div>
div to show
<div id="div1" style="display:none;" ><p>Hello</p></div>
Ok, so the thing is, you have this piece of javascript code:
window.onload = function () {
var display = document.querySelector('#time'),
timer = new CountDownTimer(5),
timeObj = CountDownTimer.parse(5);
format(timeObj.minutes, timeObj.seconds);
timer.onTick(format);
document.querySelector('button').addEventListener('click', function () {
timer.start();
});
function format(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ':' + seconds;
}
if(display.textContent == 0){
document.querySelector("#div1").style.display="block";
}
At the bottom, you have an "if" statement.
Just move that if statement into the "format" function as follow:
window.onload = function () {
var display = document.querySelector('#time'),
timer = new CountDownTimer(5),
timeObj = CountDownTimer.parse(5);
format(timeObj.minutes, timeObj.seconds);
timer.onTick(format);
document.querySelector('button').addEventListener('click', function () {
timer.start();
});
function format(minutes, seconds) {
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ':' + seconds;
console.log(display.textContent);
if(display.textContent == "00:00") {
document.querySelector("#div1").style.display="block";
}
}
};
Your code, the way it currently is, is not performing the check on every tick.
Also, you are not checking against "0". The value should be "00:00"
Of course, you can move the check to show the div into the tick event, but that is totally up to you.
I want to make a simple countdown timer which can be set by + or - and also it can be stopped and run by clicking on itself.
My problem is when it is stopped and then runs it shows NAN for the first number.
I suppose it is because of setTimer function but I don't know how to fix that.Here is my code:
var x = document.getElementsByClassName('session');
var seconds = 60;
var session;
var t;
var on = true;
var minutes = 1;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
function increase() {
minutes++;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
}
function decrease() {
minutes--;
for (var i = 0; i < x.length; i++) {
if (x[i].innerHTML > 0) {
x[i].innerHTML = minutes;
}
}
}
function setSession() {
session = x[1].innerHTML - 1;
}
function timer() {
if (seconds > 0) {
seconds--;
if (seconds == 0 && session > 0) {
session--;
seconds = 60;
}
}
x[1].innerHTML = session + ':' + seconds;
}
function stoptimer() {
clearInterval(t);
}
function general() {
if (on) {
on = false;
t = setInterval(timer, 100);
} else {
on = true;
stoptimer();
}
}
<div class='session'></div>
<div id='increase' onclick='decrease()'>-</div>
<div id='increase' onclick='increase()'>+</div>
<div class='session' onclick='setSession();general()'></div>
You shouldn't be setting session from the html entity. Basically this creates issues with parsing and could potentially break your code. Also, you subtract one every time you get this value, throwing a spanner in the works.
I re-shuffled your code a bit and added some notes, take a look:
var x = document.getElementsByClassName('session');
var seconds = 0;
var session;
var timer; // give this a useful name
var timerRunning = false; // give this a useful name
var minutes = 1;
function updateMinutes(newMinutes){
if (timerRunning){
return; // do not allow updating of countdown while count down is running
}
if(newMinutes !== undefined){ // allow this function to be called without any parameters
minutes = newMinutes;
}
if(minutes < 1){
minutes = 1; //set your minimum allowed value
}
if(minutes > 99999){
minutes = 99999; //could also have some sort of maximum;
}
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
session = minutes; // now this can only be set while timer is not running, so no need to get it from the html
//also, i would let this start at the exact same value as minutes, and have seconds start at zero
}
updateMinutes(); // call this now to initialise the display
function increase() {
updateMinutes(minutes + 1);
}
function decrease() {
updateMinutes(minutes - 1);
}
function timer_tick() {
if (seconds > 0) {
seconds--;
if (seconds == -1 && session > 0) { //because of where you've positioned your logic, this should check for negative one, no zero, otherwise you'll never display a zero seconds value
session--;
seconds = 59; //when a timer clocks over it goes to 59
}
}
if (session > 0 || seconds > 0){
x[1].innerHTML = session + ':' + seconds;
}
else{// you need to detect the ending
x[1].innerHTML = "Finished!!";
}
}
function timer_stop() {
clearInterval(timer);
}
function timer_start(){
timer = setInterval(timer_tick, 1000);
}
function timer_toggle() { //give these timer functions consistent names
if (!timerRunning) {
timer_start();
} else {
timer_stop();
}
timerRunning = !timerRunning; //just flip the boolean
}
You set
x[1].innerHTML = session + ':' + seconds;
and then try to calculate that as
session = x[1].innerHTML - 1;
You need to either put the session:seconds in another place or do
session = parseInt(x[1].innerHTML,10) - 1;
Ok, I would propose another approach. Use a class for your timer, like this:
function MyTimer(htmlEl) {
this.sec = 0;
this.min = 0;
this.elt = htmlEl;
}
MyTimer.prototype.set = function(m) {
this.min = m;
this.display();
var self = this;
this._dec = function() {
self.sec--;
if (self.sec < 0) {
if (self.min == 0) {
self.stop();
} else {
self.min -= 1;
self.sec = 59;
}
}
self.display();
}
}
MyTimer.prototype.display = function() {
this.elt.innerHTML = this.min + ":" + this.sec;
}
MyTimer.prototype.toggle = function() {
if (this.interval) {
this.stop();
this.interval = undefined;
} else this.start();
}
MyTimer.prototype.start = function() {
this.interval = setInterval(this._dec, 100);
};
MyTimer.prototype.stop = function() {
clearInterval(this.interval);
};
Then, you can use it like this:
window.onload = init;
var minutes, x, timer;
function init() {
x = document.getElementsByClassName('session');
timer = new MyTimer(x[1]);
minutes = 0;
}
function increase() {
minutes += 1;
x[0].innerHTML = minutes;
timer.set(minutes);
}
function decrease() {
minutes -= 1;
x[0].innerHTML = minutes;
timer.set(minutes);
}
function general() {
timer.toggle();
}
The only change in your html is to remove the setSession call:
<div id='timer' onclick='general()'></div>
This code is more clear. You encapsulate the logic and the min/sec in an object, which is reusable. Here is a working fiddle : https://jsfiddle.net/Shitsu/zs7osc59/.
The origin of your problem is in the code
session = x[1].innerHTML - 1;
Let's re-visit the purpose of keeping of the variable 'session'. I guess it is to keep the value of the maximum value, the upper limit of the minutes, from where to start counting, right? On the other hand, the 'minutes' variable is to keep the temporary value of the minutes. What confused you here is that you've used 'minutes' in place of it's upper limit (what actually is the session's role), in this code for example
function increase() {
minutes++;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
}
see, you are updating html by the value of 'minutes', and later you are reading that value into 'session' by that evil code:
session = x[1].innerHTML - 1;
So, why? Why you need to update the value of 'your' variable from html? You should only update the html according to the value of session var and not vice versa. Let's go on and make life simpler...
Let's keep the temporary value of minutes in 'minutes', let's also keep the upper limit in a variable session and, please, let's rename it to maxMinutes. Let's update the 'maxMinutes' only when user clicks '+' or '-' (NEVER from html).
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
</head>
<body>
<script>
var x = document.getElementsByClassName('session');
var maxMinutes = 0;
var minutes = maxMinutes;
var seconds = 0;
var timer;
var on = false;
function increase() {
if(on) {
return;
}
maxMinutes++;
minutes = maxMinutes;
x[0].innerHTML = maxMinutes;
x[1].innerHTML = minutes;
}
function decrease() {
if(on) {
return;
}
if(maxMinutes == 0)
{
return;
}
maxMinutes--;
minutes=maxMinutes;
x[0].innerHTML = maxMinutes;
x[1].innerHTML = minutes;
}
function periodicRun() {
if (seconds > 0) {
seconds--;
}
else if(seconds == 0)
{
if(minutes > 0) {
minutes--;
seconds = 60;
}
else
{
stopTimer(timer);
return;
}
}
x[1].innerHTML = minutes + ':' + seconds;
}
function stoptimer() {
clearInterval(timer);
}
function general() {
if (on) {
on = false;
stoptimer();
} else {
on = true;
timer = setInterval(periodicRun, 500);
}
}
$(document).ready(function(){
increase();
});
</script>
<div class='session'></div>
<div id='increase' onclick='decrease()'>-</div>
<div id='increase' onclick='increase()'>+</div>
<div class='session' onclick='general()'></div>
</body>
</html>
Note, that the only place where the maxLimits get's assigned a value is in increase() and decrease(). The 'minutes' and html are in their turn being updated according to maxMinutes.
Good Luck!
here is my code in which i have use readCookies function but when it's not responding, it shows nothing in the div even alert is also not working.
seconds = readCookie('countdown') || 60;
alert(seconds);
function secondPassed() {
seconds--;
var minutes = parseInt(seconds / 60);
var remainingSeconds = parseInt(seconds % 60);
if (remainingSeconds < 10) {
remainingSeconds = "0" + parseInt(remainingSeconds);
}
document.getElementById('countdown').innerHTML = minutes + " mins : " + remainingSeconds + " secs";
if (parseInt(seconds) === 0) {
alert("Time is over");
clearInterval(countdownTimer);
document.getElementById('countdown').innerHTML = "Time is Over";
document.forms["myForm"].submit();
document.location.href = "examresult.jsp";
}
}
var countdownTimer = setInterval(function () {
secondPassed();
if (seconds === 0) {
eraseCookie(seconds);
} else {
createCookie(seconds, seconds, 7);
}
}, 1000);
Store the value in a cookie or browser storage, before page unload and re-load it from cookie or browser storage in page refresh.
For example (pseudo-code):
window.onunload = function(){
set_cookie('timer', timer) /* you need to implement this function */;
}
window.onload = function() {
timer = get_cookie('timer'); /* you need to implement this function */
if ( null == timer ) timer = 0; /* not page refresh, start a new timer */
}