Why does the counter created in javascript show different values? - javascript

There is a counter that counts down from 25. When I click on the link of the page, it continues to count from wherever it is left. So when I start at 25 and exit the page, it shows 15 when I come back 10 seconds later. But when I open it with a different browser, there is a different number, so the counter does not always show the same value. What could be the reason for this and what can I do?
var interval = 25000;
function reset() {
localStorage.endTime = +new Date() + interval;
}
if (!localStorage.endTime) {
reset();
}
function millisToMinutesAndSeconds(millis) {
var seconds = ((millis % 60000) / 1000).toFixed(0);
return (seconds < 10 ? "0" : "") + seconds;
}
setInterval(function () {
var remaining = localStorage.endTime - new Date();
if (remaining >= 0) {
document.getElementById("timer").innerText =
millisToMinutesAndSeconds(remaining);
} else {
reset();
}
}, 100);

Related

Adding time on button click to a count down timer

Im creating a countdown timer which starts at 3mins and 30secs.
When the timer reaches 0 the initial 3:30 timer will be repeated.
This happens until the user presses a button, which will add 1:45 to the timer and pause the timer until the user decides to resume the timer from the new value. Eg ( 3:30 + 1:45 = 5:15).
Now I have got the first 2 step to work with my current code, but I'm having a lot of issues with the 3rd part. Once the user clicks the add 1.45 button the count works, but only up until a certain point. After this point it will start to display a negative integer.
I'm sure there is an easier way to write this code. I have really overcomplicated this. Any suggestions would be appreciated.
//Define vars to hold time values
let startingMins = 3.5;
let time = startingMins * 60;
//define var to hold stopwatch status
let status = "stopped";
//define var to holds current timer
let storeTime = null;
//define Number of sets
let setNum = 1;
//Stop watch function (logic to determin when to decrement each value)
function stopwatch () {
minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? '0' + seconds : seconds;
storeTimer = minutes + ":" + seconds; //Store time in var
storeTime = minutes + "." + seconds; //Store time in var
//Display updated time values to user
document.getElementById("display").innerHTML = storeTimer;
time--;
// When timer reachers 0 secs the inital 3:30 countdown will begin again.
if (time <= 0) {
startingMins = 3.5;
time = startingMins * 60;
minutes = Math.floor(time / 60);
seconds = time % 60;
seconds = seconds < 10 ? '0' + seconds : seconds;
setNum++;
//console.log(setNum);
}
}
function StartStop() {
if(status === "stopped") {
//start watch
interval = window.setInterval(stopwatch, 100);
var startButton = document.getElementById("start");
document.getElementById("start").innerHTML = "Pauce";
//startButton.style.display = "none"
status = "start";
//console.log(time);
}
else {
window.clearInterval(interval);
document.getElementById("start").innerHTML = "Start";
status = "stopped";
console.log(storeTime);
}
}
function pauceAdd () {
if(status === "stopped") {
//start watch
interval = window.setInterval(stopwatch, 1000);
var zukButton = document.getElementById("pauceAdd");
status = "start";
}
else {
window.clearInterval(interval);
status = "stopped";
console.log("store time " + storeTime);
let time = +storeTime + +1.45; //store time is 3.30 adding 4.75
console.log("store time2 " + time); // correct result 4.75
minutes = Math.floor(time);/// convert time from Mins (4.75) to seconds (475)
let seconds = time % 60; // 5
if (seconds < 60 ) { // if the Stored time is greater than 60 secs add 1 minute to the timer
minutes++;
seconds = seconds * 100;
console.log("secs updated = " + seconds ); // seconds updated (475)
if (seconds <= 460) {
seconds = Math.floor(seconds - 460);
console.log("seconds 2 == " + seconds)
}
else if (seconds > -60) { // Stuck here
seconds = seconds + 60;// Stuck here
}// Stuck here
else {
seconds = Math.floor(seconds - 460);
console.log("seconds 2 = " + seconds)
}
}
if (seconds < 1) {
seconds = seconds + 60;
minutes = minutes - 1;
}
seconds = seconds < 10 ? + seconds : seconds;
console.log("mins updated = " + minutes + "__________________________-");
//Display updated time values to user
document.getElementById("display").innerHTML = minutes + ":" + seconds;
}
}
function reset () {
//window.clearInterval(storeTime);
window.clearInterval(interval);
startingMins = 3.5;
time = startingMins * 60;
minutes = Math.floor(time / 60);
seconds = time % 60;
seconds = seconds < 10 ? '0' + seconds : seconds;
status = "stopped";
setNum = 1;
var startButton = document.getElementById("start");
startButton.style.display = "inline-block";
document.getElementById("display").innerHTML = "3:30";
document.getElementById("start").innerHTML = "Start";
}
I might have taken the requirements a bit too literally:
Im creating a countdown timer which starts at 3mins and 30secs.
When the timer reaches 0 the initial 3:30 timer will be repeated.
This happens until the user presses a button, which will add 1:45 to the timer and pause the timer until the user decides to resume the
timer from the new value. Eg ( 3:30 + 1:45 = 5:15).
There's a trick to countdown timers. You have to use timestamps to find out how much time ACTUALLY elapsed. You can't trust that your interval will fire exactly every second. In fact, it almost always fires a bit later (in my tests, about 2-3 milliseconds, but I was logging to the console as well, so that might have skewed the test).
let interval, timestamp;
let countdown = 210000;
document.addEventListener("DOMContentLoaded", () => {
document
.querySelector("button")
.addEventListener("click", (event) => toggleState(event.target));
});
function toggleState({ dataset }) {
timestamp = Date.now();
if (dataset.state == "running") {
clearInterval(interval);
countdown += 105000;
updateDisplay(dataset, "paused");
} else {
interval = setInterval(() => updateCountdown(dataset), 100);
updateDisplay(dataset, "running");
}
}
function updateCountdown(dataset) {
const now = Date.now();
countdown -= now - timestamp;
if (countdown <= 0) countdown = 210000;
timestamp = now;
updateDisplay(dataset, "running");
}
function updateDisplay(dataset, label) {
dataset.state = label;
dataset.time = `(${new Date(countdown).toISOString().slice(14, 19)})`;
}
button::before {
content: attr(data-state);
}
button::after {
content: attr(data-time);
padding-left: 0.5em;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" />
<button data-state="stopped" data-time="(03:30)"></button>

Countdown timer - make it persistent even after refresh or reload

I have a html page where there is counter starts on page loading. But the problem is if someone refresh or reloads the page the counter restarts. I dont know how to use local storage or cookies to make sure my counter does not reset upon reload. I am aware of the similar questions available here but my issue is i want local storage to be part of a function (countDown()).
Here is the code I tried:
<script>
var timer;
function countDown(i, callback) {
//callback = callback || function(){};
timer = setInterval(function() {
minutes = parseInt(i / 60, 10);
seconds = parseInt(i % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById("displayDiv ").innerHTML = "Time (h:min:sec) left for this station is " + "0:" + minutes + ":" + seconds;
i-- || (clearInterval(timer), callback());
}, 1000);
}
window.onload = function() {
countDown(60, function() {
$('#myModal').modal('show');
});
};
</script>
First, persist your current counter value to the session storage (with a specific key) at each iteration. You may only persist/update the value when the counter is greater than 0, and then clear the storage key once counter reached 0.
const COUNTER_KEY = 'my-counter';
function countDown(i, callback) {
//callback = callback || function(){};
timer = setInterval(function() {
minutes = parseInt(i / 60, 10);
seconds = parseInt(i % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById("displayDiv").innerHTML = "Time (h:min:sec) left for this station is " + "0:" + minutes + ":" + seconds;
if ((i--) > 0) {
window.sessionStorage.setItem(COUNTER_KEY, i);
} else {
window.sessionStorage.removeItem(COUNTER_KEY);
clearInterval(timer);
callback();
}
}, 1000);
}
Then on the window.onload function, first check if there is a value under the above key on the session storage. If a value is there, start the countdown from that value. Otherwise, start from your default value (60).
window.onload = function() {
var countDownTime = window.sessionStorage.getItem(COUNTER_KEY) || 60;
countDown(countDownTime, function() {
$('#myModal').modal('show');
});
};
You can try using localStorage as follows:
var timer;
function countDown(i, callback) {
//callback = callback || function(){};
timer = setInterval(function () {
minutes = parseInt(i / 60, 10);
seconds = parseInt(i % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById("displayDiv").innerHTML = "Time (h:min:sec) left for this station is " + "0:" + minutes + ":" + seconds;
// update the persisted time interval
localStorage.setItem('timeLeft', i);
i-- || (clearInterval(timer), callback());
}, 1000);
}
window.onload = function () {
let timeInterval = 100;
//check if you have the last counter value
let timeLeft = localStorage.getItem('timeLeft');
if (isNaN(timeLeft)) {
//save the current interval
localStorage.setItem('timeLeft', timeInterval);
} else if (timeLeft == 0) {
//save the current interval
localStorage.setItem('timeLeft', timeInterval);
} else {
// take the last saved value
timeInterval = timeLeft;
}
countDown(timeInterval, function () {
$('#myModal').modal('show');
});
};
I think what you want is a property called sessionStorage which stores information in the browser permanently.
here's a link explaining it
https://www.w3schools.com/jsref/prop_win_sessionstorage.asp
I have a made a promise based function for this.
It uses localStorage to store the countdown every 1 second and, once the time is over, it returns you a promise.
I use it with React and React Router on production, it's been working great.
function countdown(interval = 5000) {
return new Promise(async (resolve, reject) => {
let intervalLoop = null
function countTimer() {
if (!localStorage.endTime) {
localStorage.endTime = +new Date() + interval
}
let remaining = localStorage.endTime - new Date()
if (remaining >= 0) {
let currentTime = Math.floor(remaining / 1000)
console.log("Countdown current time:", currentTime)
} else {
clearInterval(intervalLoop)
resolve(true)
}
}
intervalLoop = setInterval(countTimer, 1000)
})
}
Make sure you are inside an async function to use it:
(async _ => {
console.log("Countdown starts now...")
await countdown(5000)
console.log("Countdown is over!");
})()

How to initialize a countdown timer to reflect the user input

I'm creating a countdown timer based on a users input. When the user pauses and resumes, the timer restarts at the initial inputed value and fails to resume from the current interval. I've uploaded the code into Codepen.
http://codepen.io/alivera/pen/JGpvRx
//Timer
var myTimer;
var duration = sessionCounter * 60;
var startTimer = function() {
minutes = parseInt(duration / 60);
seconds = parseInt(duration % 60);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById("clockTimer").innerHTML = minutes + ":" + seconds;
if (--duration < 0) {
document.getElementById("toggleStatus").innerHTML = "<br>Break!";
}
};
//Start Timer
var go = function() {
myTimer = setInterval(startTimer, 1000);
document.getElementById('start').innerHTML = "Stop";
document.getElementById('start').className = "btn btn-danger";
document.getElementById("start").onclick = stop;
};
//Stop Timer
var stop = function() {
clearInterval(myTimer);
document.getElementById('start').innerHTML = "Start";
document.getElementById('start').className = "btn btn-success";
document.getElementById("start").onclick = go;
};
duration.onload = stop();
You're loading the time to count down from from the #clockTimer element:
var sessionCounter = document.getElementById("clockTimer").innerHTML;
This is bad because the contents of that element are changing. Often.
And parseInt on the next line only is only giving you the number before the colon. Your best bet for solving this problem would be storing the current time remaining and the previously set time in separate variables, as I have done below.
Your code was a little difficult to work with, so while correcting the error(s), I ended up almost completely rewriting it.
Here's my version; I'll explain it line-by-line (or section-by-section, or whatever):
First, put all of our elements in to easy-to-use (and type) variables:
var subBreakButton = document.getElementById("subBreakButton"),
breakTimer = document.getElementById("breakTimer"),
addBreakButton = document.getElementById("addBreakButton"),
subSessionButton = document.getElementById("subSessionButton"),
sessionTimer = document.getElementById("sessionTimer"),
addSessionButton = document.getElementById("addSessionButton"),
breakSession = document.getElementById("breakSession"),
clockTimer = document.getElementById("clockTimer"),
These variables are in seconds (thus m * s):
breakLength = 5 * 60, // Minutes to seconds
sessionLength = 25 * 60, // Minutes to seconds
sessionTimeLeft = sessionLength;
Next, a helper method that formats times into a mm:ss ... format:
function timeString (seconds) {
var minutes = parseInt(seconds / 60) + "",
seconds = parseInt(seconds % 60) + "";
if (minutes.length === 1)
minutes = "0" + minutes;
if (seconds.length === 1)
seconds = "0" + seconds;
return minutes + ":" + seconds;
}
Third, event listeners for the plus and minus buttons:
// Event Listeners
addBreakButton.addEventListener("click", function () {
breakLength += 1 * 60;
breakTimer.innerHTML = timeString(breakLength);
});
subBreakButton.addEventListener("click", function () {
breakLength -= 1 * 60;
if (breakLength < 0)
breakLength = 0;
breakTimer.innerHTML = timeString(breakLength);
});
addSessionButton.addEventListener("click", function () {
sessionLength += 1 * 60;
sessionTimer.innerHTML = timeString(sessionLength);
});
subSessionButton.addEventListener("click", function () {
sessionLength -= 1 * 60;
if (sessionLength < 0)
sessionLength = 0;
sessionTimer.innerHTML = timeString(sessionLength);
});
And, the fun part:
// Timer
var myTimer;
function startTimer () {
if (myTimer) // Check to see if a timer was already running, and if so, stop it
stopTimer();
sessionTimeLeft = sessionLength;
myTimer = setInterval(function () {
sessionTimeLeft--;
if (sessionTimeLeft <= 0) {
sessionTimeLeft = 0;
stopTimer();
}
clockTimer.innerHTML = (sessionTimeLeft <= 0? "Break!": timeString(sessionTimeLeft));
}, 1000);
}
function stopTimer () {
clearInterval(myTimer);
myTimer = 0;
}
Lastly, wrappers:
// Start Timer
function go() {
startTimer();
}
//Pause Timer
function stop() {
stopTimer();
}
Codepen: http://codepen.io/anon/pen/ZQjLZE?editors=1010

How to repeat javascript setInterval timer infinitely with two times

I am working on a timer that runs for a set amount of minutes, then starts over for a break period that counts down and then goes back to the original amount of minutes. I'm struggling with the logic. So far, I have it running down the original time, then running down the break timer but I need help making it return to the original time and loop this infinitely (or until the stop button is pressed). Here's what I have:
function timer(minutes, breakLength) {
--minutes;
timerId = setInterval(function() {
if (minutes >= 0) {
if (seconds > 0) {
--seconds;
}
if (seconds == 0 && minutes == 0) {
playSound();
isBreak = true;
minutes = breakLength;
$('.type').html('Break');
$('.timer').html(minutes + ':00');
};
if (seconds === 0) {
seconds = 59;
--minutes;
}
if (seconds < 10) {
seconds = '0' + seconds;
}
$('.timer').html(minutes + ':' + seconds);
}
}, 1000);
}
How can I make this repeat itself?
Define a new variable as a timeout id holder (let's call it resetTimeout) in your timer function scope:
var resetTimeout = null;
Add this additional code to the main function
var runFor = 60000; // 60000ms or 1 minute
Add logic in the main interval (first line):
if(runFor <= 0) {
if(!resetTimeout) {
// Create a reset timeout
resetTimeout = setTimeout(function(){ runFor = 60000; resetTimeout = null; }, breakLength);
}
return;
}
else {
runFor -= 1000; // Deduct time of this interval
}
This logic deducts 1000 ms or 1 second from runFor until it is fully consumed. Then creates a timeOut function that will reset it back to its original value and returns the current function until runFor is renewed. I used 60000 ms as an example and you can see the correct version in the full code below. Why do we assign the timeout to a variable? It is simple, we don't want to create more than one timeout. We'll set the timeout to null to allow recreation on the next interval.
Note that there are better ways of doing this but I decided to make as little modifications to your code as possible.
Here is the working code:
function timer(minutes, breakLength) {
var seconds = 0;
var originalMinutes = minutes;
var resetTimeout = null;
var totalRunFor = minutes * 60 * 1000; // Since minutes are independent
var runFor = totalRunFor;
timerId = setInterval(function() {
if(runFor <= 0) {
if(!resetTimeout) {
// Create a reset timeout
resetTimeout = setTimeout(function(){ runFor = totalRunFor; resetTimeout = null; }, breakLength);
}
return;
}
else {
runFor -= 1000; // Deduct time of this interval
}
if (minutes >= 0) {
if (seconds > 0) {
--seconds;
}
if (seconds == 0 && minutes == 0) {
//playSound();
isBreak = true;
minutes = originalMinutes;
$('.type').html('Break');
$('.timer').html(minutes + ':00');
};
if (seconds === 0) {
seconds = 59;
--minutes;
}
$('.timer').html(minutes + ':' + ((seconds < 10)?'0':'') + seconds);
}
}, 1000);
}
timer(1, 10000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Run for a minute and stop for 10 seconds indefinitely.
<div class='type'></div>
<div class='timer'></div>
It may be conceptually easier to seperate this into multiple functions within the timer function
function timer(minutes, breakLength) {
var ci = null;
function ACountdown(minutes, callback) {
var mm = minutes,
ss = 0;
ci = setInterval(function () {
--ss;
if (ss < 0)
ss += 60, --mm;
if (mm < 0) {
// done
clearInterval(ci);
setTimeout(callback, 0);
} else {
$('.timer').html(mm + ':' + seconds);
}
}, 1e3);
}
function A() {
// returned from break
$('.type').html = 'Countdown';
ACountdown(minutes, B);
}
function B() {
// just finished countdown
playSound();
// going on break
$('.type').html = 'Break';
ACountdown(breakLength, A);
}
// set up any click handlers here, e.g.
document.getElementById('cancel_button').addEventListener('click', function c() {
this.removeEventListener('click', c);
clearInterval(ci);
});
// start invocation chain
A();
}

How can I make this JavaScript Timer function properly?

I am trying to make a timer using JavaScript. The problem is, I can't get the timer to stop when it reaches 0. I have tried using return and if statements, but nothing seems to be working. Am I on the right track, or is there a better way to do this?
<input type="text" id="minutes" style="width:30px;text-align:center" maxlength="2" placeholder="00">
<span>:</span>
<input type="text" id="seconds" style="width:30px;text-align:center" maxlength="2" placeholder="00">
<button onclick="timer()">Set</button>
<script>
//This prototype correctly uses the modulus function when dealing with negative numbers.
Number.prototype.mod = function (m) {
return ((this % m) + m) % m
}
function timer() {
var minutes = document.getElementById('minutes').value //Value of minutes box.
var seconds = document.getElementById('seconds').value //Value of seconds box.
var initial = seconds * 1000 //Amount of seconds (converted to milliseconds) initially set.
var milliseconds = (minutes * 60000) + (seconds * 1000) //Total amount of milliseconds set.
setTimeout(function () {
alert("Time's up!")
}, milliseconds) //Display a message when the set time is up.
/*\Decreases the minute by one after the initially set amount of seconds have passed.
|*|Then, clears the interval and sets a new one to decrease the minute every 60 seconds.
\*/
test = setInterval(function () {
minutes--;
document.getElementById('minutes').value = minutes;
clearInterval(test)
setInterval(function () {
minutes--;
document.getElementById('minutes').value = minutes
}, 60000)
}, initial)
//Seconds are set to decrease by one every 1000 milliseconds, then be displayed in the seconds box.
setInterval(function () {
seconds--;
document.getElementById('seconds').value = seconds.mod(60)
}, 1000)
}
You have four different timer functions (setTimer and two setIntervals) when you only need one. JSFiddle
function timer() {
var minutes = document.getElementById('minutes').value //Value of minutes box.
var seconds = document.getElementById('seconds').value //Value of seconds box.
var intervalTimer = setInterval(function () {
seconds--;
if (seconds < 0) {
seconds = 59;
minutes--;
}
document.getElementById('minutes').value = minutes;
document.getElementById('seconds').value = seconds;
if (minutes == 0 && seconds == 0) {
alert("Time's up!");
clearInterval(intervalTimer);
}
}, 1000);
}
In general, you need to make sure every setInterval is given a name (var x = setInterval...) and cleared later on (clearInterval(x)). You could have separate timers (one for the minutes which starts after the given number of seconds then repeats every 60 seconds, one for seconds, and one to display the message) if you really want to for some reason, as long as you clear all of the interval timers once the countdown reaches zero.
Using two timers might make sense, however. This would make sure that the Time's up message really appears when it's supposed to, even if there is any imprecision in the interval timer.
function timer() {
var minutes = document.getElementById('minutes').value,
seconds = document.getElementById('seconds').value,
intervalTimer = setInterval(function () {
seconds--;
if (seconds < 0) {
seconds = 59;
minutes--;
}
document.getElementById('minutes').value = minutes;
document.getElementById('seconds').value = seconds;
}, 1000);
setTimer(function () {
alert("Time's up!");
clearInterval(intervalTimer);
}, minutes * 60000 + seconds * 1000);
}
I made improvements to Stuart's answer: fiddle
Basically the same thing, except it works properly:
function clearTimer() {
clearInterval(intervalTimer);
}
var intervalTimer;
function timer() {
var minutes = document.getElementById('minutes').value //Value of minutes box.
var seconds = document.getElementById('seconds').value //Value of seconds box.
intervalTimer = setInterval(function () {
seconds--;
if (seconds < 0) {
seconds += 60;
minutes--;
}
if (minutes < 0) {
alert("Time's up!");
clearTimer();
} else {
document.getElementById('minutes').value = minutes;
document.getElementById('seconds').value = seconds;
}
}, 1000);
}
Im not a great javascript guy, but maybe this will help. i made this in typescript http://www.typescriptlang.org/Playground/
but i would do timing different and use the javascript date object and calculate differences. This is a simple example of how i would start to create a time (without the date object)
javascript
var Timer = (function () {
function Timer(time) {
this.accuracy = 1000;
this.time = time;
}
Timer.prototype.run = function (button) {
var _this = this;
this.time -= 1; //this is inaccurate, for accurate time use the date objects and calculate the difference.
//http://www.w3schools.com/js/js_obj_date.asp
button.textContent = this.time.toString();
if (this.time > 0) {
setTimeout(function () {
return _this.run(button);
}, 1000);
}
};
return Timer;
})();
var time = new Timer(10);
var button = document.createElement('button');
time.run(button);
document.body.appendChild(button);
typescript(in case you wonder)
class Timer {
accuracy = 1000;//update every second
time: number;
constructor(time: number) {
this.time = time;
}
run(button: HTMLButtonElement) {
this.time -=1;//this is inaccurate, for accurate time use the date objects and calculate the difference.
//http://www.w3schools.com/js/js_obj_date.asp
button.textContent = this.time.toString();
if(this.time > 0)
{
setTimeout(()=> this.run(button),1000);
}
}
}
var time = new Timer(10)
var button = document.createElement('button');
time.run(button);
document.body.appendChild(button);

Categories