I've been working on a timer for a few weeks now. When I try to subtract minutes from 0, it goes into negatives without touching the hours. I've tried a few methods, read the documentation, and watched several YouTube videos, but none of them help me. Here's the code I used:
seconds--;
if (seconds === 0) {
seconds = 59;
minutes--;
if (minutes < 10) {
minutesText.innerText = '0' + minutes.toString()
} else {
minutesText.innerText = minutes;
}
if (minutes === 0) {
minutes = 59;
hours--;
if (hours < 10) {
hoursText.innerText = '0' + hours.toString()
} else {
hoursText.innerText = hours;
}
if (hours === 0) {
window.clearInterval(interval);
}
}
}
if (seconds < 10) {
secondsText.innerText = '0' + seconds.toString();
} else {
secondsText.innerText = seconds;
}
It never touches the hours-- and doesn't make minutes be equal to 59.
(Sorry if it's an easy fix, I'm just getting started on JS)
You have a couple of problems:
You're updating minutesText.innerText before you check whether minutes is 0 and thus needs to be changed to 59. It should be after the if (minutes === 0) block instead.
You need to check if values are 0 before you decrement them, otherwise you will never catch the 0 value.
This snippet incorporates those fixes.
let hoursText = document.getElementById('hours');
let minutesText = document.getElementById('minutes');
let secondsText = document.getElementById('seconds');
function updateTimer() {
hours = +hoursText.innerText;
minutes = +minutesText.innerText;
seconds = +secondsText.innerText;
if (seconds === 0) {
seconds = 59;
if (minutes === 0) {
minutes = 59;
if (hours === 0) {
window.clearInterval(interval);
return;
} else {
hours--;
}
if (hours < 10) {
hoursText.innerText = '0' + hours.toString()
} else {
hoursText.innerText = hours;
}
} else {
minutes--;
}
if (minutes < 10) {
minutesText.innerText = '0' + minutes.toString()
} else {
minutesText.innerText = minutes;
}
} else {
seconds--;
}
if (seconds < 10) {
secondsText.innerText = '0' + seconds.toString();
} else {
secondsText.innerText = seconds;
}
}
interval = setInterval(updateTimer, 1000);
<div><span id="hours">00</span>:<span id="minutes">01</span>:<span id="seconds">13</span></div>
Related
I am currently learning JS and trying to build a simple stopwatch for practice. It has 2 buttons - RESET and START:
HTML:
<section class="stopwatch">
<div class="numbers">00:00:00</div>
<ul class="buttons">
<li>
<button class="btn reset">RESET</button>
</li>
<li>
<button class="btn btn-start start">START</button>
</li>
</ul>
</section>
What I am trying to do is when user clicks the "START" button the stopwatch starts and the button becomes "STOP". Then when clicked again the stopwatch stops or pauses to its current position and the button again becomes "START" and so on.
What I am struggling with is the second click to pause the stopwatch.
This is what I got so far:
let seconds = '00';
let minutes = '00';
let hours = '00';
let startStopwatch;
function startTimer() {
seconds = Number(seconds) + 1;
if (seconds < 10) {
seconds = '0' + seconds;
} else if (seconds === 60) {
seconds = '00';
minutes = Number(minutes) + 1;
}
if (typeof minutes === 'number' && Number(minutes) < 10) {
minutes = '0' + minutes;
}
if (Number(minutes) === 60) {
minutes = '00';
hours = Number(hours) + 1;
}
if (typeof hours === 'number' && Number(hours) < 10) {
hours = '0' + hours;
}
document.querySelector(
'.numbers'
).textContent = `${hours}:${minutes}:${seconds}`;
}
document.querySelector('.start').addEventListener('click', function () {
startStopwatch = setInterval(startTimer, 1000);
document.querySelector('.start').textContent = 'STOP';
});
document.querySelector('.reset').addEventListener('click', function () {
clearInterval(startStopwatch);
seconds = '00';
minutes = '00';
hours = '00';
document.querySelector(
'.numbers'
).textContent = `${hours}:${minutes}:${seconds}`;
});
The other way is to use flag variable. The bStart variable of bool type is used. It will work for you well. Also when the reset button is clicked, the "STOP" text should be changed into "START".
let seconds = '00';
let minutes = '00';
let hours = '00';
let startStopwatch;
let bStart = false;
function startTimer() {
seconds = Number(seconds) + 1;
if (seconds < 10) {
seconds = '0' + seconds;
} else if (seconds === 60) {
seconds = '00';
minutes = Number(minutes) + 1;
}
if (typeof minutes === 'number' && Number(minutes) < 10) {
minutes = '0' + minutes;
}
if (Number(minutes) === 60) {
minutes = '00';
hours = Number(hours) + 1;
}
if (typeof hours === 'number' && Number(hours) < 10) {
hours = '0' + hours;
}
document.querySelector(
'.numbers'
).textContent = `${hours}:${minutes}:${seconds}`;
}
document.querySelector('.start').addEventListener('click', function () {
if(!bStart) {
bStart = true;
startStopwatch = setInterval(startTimer, 1000);
document.querySelector('.start').textContent = 'STOP';
} else {
bStart = false;
clearInterval(startStopwatch);
document.querySelector('.start').textContent = 'START';
}
});
document.querySelector('.reset').addEventListener('click', function () {
clearInterval(startStopwatch);
seconds = '00';
minutes = '00';
hours = '00';
document.querySelector(
'.numbers'
).textContent = `${hours}:${minutes}:${seconds}`;
document.querySelector('.start').textContent = 'START';
bStart = false;
});
So I am trying to make a timer on Javascript, I'm new so it is very basic. I have it working so that the minutes and the seconds change correctly but when I try to do it in a loop it messes it up. Any help would be great.
var seconds = 5;
var minutes = 3;
function countdown() {
for (i = 0; i < 3; i++) {
if (seconds > 0) {
seconds--;
setTimeout("countdown()", 1000);
} else if (seconds <= 0) {
minutes--;
seconds = 5;
}
}
document.getElementById("timer").innerHTML = minutes + "M " + seconds + "S";
}
countdown();
<p id="timer"></p>
function startCountdown(minutes, seconds) {
updateElement()
var timerId = setInterval(function() {
if(--seconds < 0) {
seconds = 59
--minutes
}
if(minutes <= 0 && seconds <=0 ) {
clearInterval(timerId)
minutes = seconds = 0
}
updateElement()
}, 1000);
function updateElement() {
document.getElementById("timer").innerHTML = minutes + "M " + seconds + "S"
}
}
startCountdown(5, 3)
<p id="timer"></p>
this is my code, it doesn't work I think the problem is what I'm returning in the function.
Please, help.
var minutes = 25;
var seconds = 60;
function myFunction() {
var start = setInterval(function() {
if (seconds > 0) {
seconds--;
}
if (seconds == 0) {
seconds = 60;
minutes--;
}
if (seconds == 0 && minutes == 0) {
alert("done");
}
var time = minutes + ":" + seconds;
return time;
}, 1000);
return start;
}
console.log(myFunction());
Description
Minor changes to show your code is working
Bugs?
- Requires a minutes and seconds variable be declared before myFunction is called, the rewrite takes these are parameters.
- Doesn't check if the variables are negative and thereby expects "valid" data from the user.
- Only allows for console.log(time), the rewrite allows a function to be passed in for each tick and onTimerComplete
var minutes = 25;
var seconds = 60;
function myFunction() {
var start = setInterval(function() {
if (seconds > 0) {
seconds--;
}
if (seconds == 0 && minutes == 0) {
alert("done");
// added this to clear the timer on 0 minutes 0 seconds
clearInterval(start);
return;
}
if (seconds == 0) {
seconds = 59;
minutes--;
}
var time = minutes + ":" + seconds;
// adding this as this is the function being repeated
console.log(time);
}, 1000);
}
myFunction();
How I would rewrite this
function timer(minutes, seconds, onTimerChanged, onTimerComplete) {
var timerPointer = undefined;
// if minutes is below 0 reset to 0
if (minutes < 0) {
minutes = 0;
}
// if seconds is set below 0 reset to 0
if (seconds < 0) {
seconds = 0;
} else if (seconds > 59) {
// this will add to minutes if too many seconds are passed
minutes += Math.floor(seconds / 60);
seconds = seconds % 60;
}
// this is the function to be called on each tick call
// default: console.log
if (onTimerChanged === undefined) {
onTimerChanged = console.log;
}
if (onTimerComplete === undefined) {
onTimerComplete = function() {
console.log("done")
};
}
// starts the timer
this.start = function() {
timerPointer = setInterval(tick, 1000);
}
// stops the timer
this.stop = clearInterval(timerPointer);
this.time = undefined;
// function for each tick
function tick() {
if (seconds > 0) {
seconds--;
}
if (seconds == 0 && minutes == 0) {
// added this to clear the timer on 0 minutes 0 seconds
clearInterval(timerPointer);
if (onTimerComplete) {
onTimerComplete();
}
return;
}
if (seconds == 0) {
seconds = 59;
minutes--;
}
// pads the numbers so they are always two digits
this.time = padToTwo(minutes) + ":" + padToTwo(seconds);
// if onTimeChanged exists call it
if (onTimerChanged) {
onTimerChanged(this.time);
}
}
// padding the string to be two digits always
function padToTwo(number) {
if (number <= 99) {
number = ("0" + number).slice(-2);
}
return number;
}
}
// create the timer object
var test = new timer(-1, 500);
// start the timer
test.start();
// this would also work
// new timer(minutes, seconds).start();
Both of the returns you have are pointless. console.log() will only output one time. You have to have console.log() inside of the setInterval() function to run multiple times. You should also clear the interval to avoid any memory leaks.
Last, I also added in minutes > 0 because otherwise seconds would be 60 and minutes would be -1 when time has run out.
var minutes = 25;
var seconds = 60;
function myFunction() {
var start = setInterval(function() {
if (seconds > 0) {
seconds--;
}
if (seconds == 0 && minutes > 0) {
seconds = 60;
minutes--;
} else
if (seconds == 0 && minutes == 0) {
clearInterval(start);
alert("done");
}
var time = minutes + ":" + seconds;
console.log(time);
}, 1000);
}
myFunction();
Your code (almost) works. You just will have to wait 26 minutes to see the alert.
if (seconds == 0 && minutes == 0) {
clearInterval(start);
alert("done");
}
Everything I have so far is working great, although I'd like an alert that will display the amount of time used on the timer.
Example, starting timer at 00:10 and stopping at -00:20, the message alert should say 30 seconds
My problem is stopTimer() which is the STOP button, on click it should display the amount of seconds, minutes however I'm having trouble with.
How can I form minutes in there as well, if the client went that long? JsFiddle
var totseconds = 10;
var seconds = totseconds;
function floor(x) {
return x | 0;
}
function pad(n) {
if (n < 0) {
n = -n;
}
if (n < 10) {
return '0' + n.toString();
}
return n.toString();
}
function stopTimer() {
clearTimeout(countdownTimer);
if (seconds > 60) {
var rs = seconds % 60;
var m = seconds / 60;
windows.alert((totalseconds / 60) - (m + 1) + " minutes and " + totalseconds - (rs + 1) + " seconds")
}
//else {window.alert((seconds +1)+ " seconds");}
else {
window.alert(totseconds - (seconds + 1) + " seconds");
}
}
function secondPassed() {
var minutes = pad(floor(seconds / 60));
if (seconds < 0) {
minutes = '-' + minutes;
}
var remainingSeconds = pad(seconds % 60);
document.getElementById('countdown').innerHTML = minutes + ":" + remainingSeconds;
if (seconds > 0) {
seconds--;
if (seconds > 8) {
document.body.style.backgroundColor = "green";
} else if (seconds == 5) {
document.body.style.backgroundColor = "yellow";
}
} else {
document.body.style.backgroundColor = "red";
if (seconds % 2 == 0) {
document.getElementById('skull').style.display = "block";
}
if (seconds % 2 != 0) {
document.getElementById('skull').style.display = "none";
}
seconds--;
}
}
<img id="skull" src="http://s15.postimg.org/es5w3xpob/skull.gif" style="position:absolute; z-index: -1;display:none;">
<div style=" z-index:10;">
<p align="center"> <span id="countdown" style="color:black; font-size: 50px; font-weight: bold;"></span>
</br>
<button onclick="countdownTimer = setInterval('secondPassed()', 1000)">Start</button>
<button onclick="stopTimer()">Stop</button>
</p>
</div>
Confusion caused by counting seconds backwards seems to be the problem. On the fiddle in function stopTimer() changing
if (seconds > 60) { // .... more than a minute
to
if(seconds < -60) { // ... more than a minute
causes code for over a minute to get executed (which as written has errors and will need debugging). To clarify the logic and make coding easier when counting backwards may I suggest calculating something like
var elapsedSeconds = - (seconds - totseconds);
I've got here a countdown, for testing purposes I have it set for 10 seconds, but once It's perfected I'll have it as 30 minutes. Everything runs smoothly until the countdown goes negative, I want it to be negative, but in a proper format and for it to not jump from 0 to -01:00. Math.Floor seemed like a good idea, but with this code it ran with negative numbers right away. Also, once it is negative the format is -00:0-0, I would like -00:00.
How can the format be fixed once it's negative?
Please, refrain from object orientated, our web server is several years out of date.
var seconds = 10;
function secondPassed() {
var minutes = Math.round((seconds - 30)/60);
var remainingSeconds = seconds % 60;
if (remainingSeconds < 10)
{
remainingSeconds = "0" + remainingSeconds;
}
document.getElementById('countdown').innerHTML = minutes + ":" + remainingSeconds;
if (seconds > 0) {
seconds--;
if (seconds > 8) {
document.body.style.backgroundColor = "green"; }
else if (seconds == 8) {document.body.style.backgroundColor = "yellow";}
else if (seconds == 3) {document.body.style.backgroundColor = "red";}
}
else{
seconds--;
}
}
var countdownTimer = setInterval('secondPassed()', 1000);
<body onload = "getSeconds()">
<p align ="center">
<span id="countdown" style="color:black; font-size: 20px; font-weight: bold"> </span>
</p>
</body>
Here is a floor function that rounds -0.5 to 0, and -1.5 to -1, as you require:
function floor(x) {
return x | 0;
}
Here is a padding function that correctly pads an integer with 0s:
function pad(n) {
if (n < 0) {
n = -n;
}
if (n < 10) {
return '0' + n.toString();
}
return n.toString();
}
Your code becomes:
<html>
<head>
<title>Countdown</title>
<script type="text/javascript">
var seconds = 10;
function floor(x) {
return x | 0;
}
function pad(n) {
if (n < 0) {
n = -n;
}
if (n < 10) {
return '0' + n.toString();
}
return n.toString();
}
function secondPassed() {
var minutes = pad(floor(seconds/60));
if (seconds < 0) {
minutes = '-' + minutes;
}
var remainingSeconds = pad(seconds % 60);
document.getElementById('countdown').innerHTML = minutes + ":" + remainingSeconds;
if (seconds > 0) {
seconds--;
if (seconds > 8) {
document.body.style.backgroundColor = "green"; }
else if (seconds == 8) {document.body.style.backgroundColor = "yellow";}
else if (seconds == 3) {document.body.style.backgroundColor = "red";}
}
else{
seconds--;
}
}
var countdownTimer = setInterval('secondPassed()', 1000);
</script>
</head>
<body onload = "getSeconds()">
<p align ="center">
<span id="countdown" style="color:black; font-size: 20px; font-weight: bold"> </span>
</p>
</body>
</html>
I think the simplest way is to always treat seconds as positive, but then display a - if it is, in fact, negative:
var abs_seconds = Math.abs(seconds);
var is_negative = seconds < 0;
var minutes = Math.round((abs_seconds - 30)/60);
var remainingSeconds = abs_seconds % 60;
if (remainingSeconds < 10)
{
remainingSeconds = "0" + remainingSeconds;
}
document.getElementById('countdown').innerHTML = (is_negative ? '-' : '') + minutes + ":" + remainingSeconds;
seconds--;
if (!is_negative) {
if (seconds > 8) {
document.body.style.backgroundColor = "green";
} else if (seconds == 8) {
document.body.style.backgroundColor = "yellow";
} else if (seconds == 3) {
document.body.style.backgroundColor = "red";
}
}
https://jsfiddle.net/sdd8ubxh/2/
For the rounding, I think using parseInt() rather than Math.floor() will get you what you're looking for (truncation).
As for the format, I think you will need to check whether remaining seconds is less than 0:
var isNegative = false;
if(seconds < 0)
{
isNegative = true;
remainingSeconds = Math.abs(remainingSeconds);
}
And then later prepend "-" if isNegative.