How can I make this JavaScript Timer function properly? - javascript

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);

Related

Why does the counter created in javascript show different values?

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);

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 to write a countdown timer in JavaScript? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Just wanted to ask how to create the simplest possible countdown timer.
There'll be a sentence on the site saying:
"Registration closes in 05:00 minutes!"
So, what I want to do is to create a simple js countdown timer that goes from "05:00" to "00:00" and then resets to "05:00" once it ends.
I was going through some answers before, but they all seem too intense (Date objects, etc.) for what I want to do.
I have two demos, one with jQuery and one without. Neither use date functions and are about as simple as it gets.
Demo with vanilla JavaScript
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
window.onload = function () {
var fiveMinutes = 60 * 5,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
<body>
<div>Registration closes in <span id="time">05:00</span> minutes!</div>
</body>
Demo with jQuery
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.text(minutes + ":" + seconds);
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
jQuery(function ($) {
var fiveMinutes = 60 * 5,
display = $('#time');
startTimer(fiveMinutes, display);
});
However if you want a more accurate timer that is only slightly more complicated:
function startTimer(duration, display) {
var start = Date.now(),
diff,
minutes,
seconds;
function timer() {
// get the number of seconds that have elapsed since
// startTimer() was called
diff = duration - (((Date.now() - start) / 1000) | 0);
// does the same job as parseInt truncates the float
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (diff <= 0) {
// add one second so that the count down starts at the full duration
// example 05:00 not 04:59
start = Date.now() + 1000;
}
};
// we don't want to wait a full second before the timer starts
timer();
setInterval(timer, 1000);
}
window.onload = function () {
var fiveMinutes = 60 * 5,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
<body>
<div>Registration closes in <span id="time"></span> minutes!</div>
</body>
Now that we have made a few pretty simple timers we can start to think about re-usability and separating concerns. We can do this by asking "what should a count down timer do?"
Should a count down timer count down? Yes
Should a count down timer know how to display itself on the DOM? No
Should a count down timer know to restart itself when it reaches 0? No
Should a count down timer provide a way for a client to access how much time is left? Yes
So with these things in mind lets write a better (but still very simple) CountDownTimer
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
};
};
So why is this implementation better than the others? Here are some examples of what you can do with it. Note that all but the first example can't be achieved by the startTimer functions.
An example that displays the time in XX:XX format and restarts after reaching 00:00
An example that displays the time in two different formats
An example that has two different timers and only one restarts
An example that starts the count down timer when a button is pressed
You can easily create a timer functionality by using setInterval.Below is the code which you can use it to create the timer.
http://jsfiddle.net/ayyadurai/GXzhZ/1/
window.onload = function() {
var minute = 5;
var sec = 60;
setInterval(function() {
document.getElementById("timer").innerHTML = minute + ":" + sec;
sec--;
if (sec == 00) {
minute--;
sec = 60;
if (minute == 0) {
minute = 5;
}
}
}, 1000);
}
Registration closes in <span id="timer">5:00</span>!
If you want a real timer you need to use the date object.
Calculate the difference.
Format your string.
window.onload=function(){
var start=Date.now(),r=document.getElementById('r');
(function f(){
var diff=Date.now()-start,ns=(((3e5-diff)/1e3)>>0),m=(ns/60)>>0,s=ns-m*60;
r.textContent="Registration closes in "+m+':'+((''+s).length>1?'':'0')+s;
if(diff>3e5){
start=Date.now()
}
setTimeout(f,1e3);
})();
}
Example
Jsfiddle
not so precise timer
var time=5*60,r=document.getElementById('r'),tmp=time;
setInterval(function(){
var c=tmp--,m=(c/60)>>0,s=(c-m*60)+'';
r.textContent='Registration closes in '+m+':'+(s.length>1?'':'0')+s
tmp!=0||(tmp=time);
},1000);
JsFiddle

Jquery building multiple timers and .each(function() {

I am trying to build multiple timers for my web page, so far I have,
$('.timer').each(function() {
var timer = setInterval(function() {
var time = $(this).text().split(':');
var minutes = parseInt(time[0], 10);
var seconds = parseInt(time[1], 10);
// TIMER RUN OUT
if (!minutes && !seconds) {
// CLEAR TIMER
clearInterval(timer);
// MINUS SECONDS
} else {
seconds -= 1;
}
// MINUS MINUTES
if (seconds < 0 && minutes != 0) {
minutes -= 1;
seconds = 59;
// ADD ZERO IF SECONDS LESS THAN 10
} else {
if (seconds < 10) {
seconds = '0' + seconds;
}
}
// ADD ZERO IF MINUTES LESS THAN 10
if (minutes < 10) {
minutes = '0' + minutes;
}
}, 1000);
});
This doesn't work though! Where am I going wrong!
Thanks
First, inside your setInterval callback, this no longer refers to the .timer element. Try changing that to self and add var self = this; before the call to setInterval. Second, you never write your time back to your .timer element.
Are you trying to display a clock counting down? In that case, you're not updating the text after all the calculations. Try adding:
$(this).text(minutes+':'+seconds);

Categories