How do I stop and reset a setInterval timer - javascript

How do I stop and reset this setInterval timer back to 00:00?
Setting clearInterval(timer); works for stopping the time but I can't figure out how to reset the time value back to 00:00.
Here's where I'm at:
HTML
<span class="timer">
<label id="minutes">00</label>:<label id="seconds">00</label>
</span>
JS
const minutesLabel = document.getElementById("minutes");
const secondsLabel = document.getElementById("seconds");
let timer = setInterval(setTime, 1000);
function setTime() {
++totalSeconds;
secondsLabel.innerHTML = pad(totalSeconds % 60);
minutesLabel.innerHTML = pad(parseInt(totalSeconds / 60));
}
function pad(val) {
let valString = val + "";
if (valString.length < 2) {
return "0" + valString;
} else {
return valString;
}
}
stopTimer = () => {
clearInterval(timer);
timer = setInterval(setTime, 1000);
};
I'm using this timer in a game so based on the users state I need to be able start, stop, and restart the time back to 0.

What's happening now is that your variable keeps going up, even when you "reset" the timer.
Simply add
totalSeconds = 0;
to your stopTimer function. This will reset the variable to zero.

The variable totalSeconds keeps track of your time.
The name of your function stopTimer() - maybe it should be restartTimer - seems a bit misleading since you're restarting the timer there but basically just set totalSeconds to 0 like:
stopTimer = () => {
totalSeconds = 0;
clearInterval(timer);
timer = setInterval(setTime, 1000);
};

Related

seeking explanation for timer tutorial

Hi everyone I am new to JavaScript and was watching some tutorials on the stopwatch in javascript I manage to understand most of the code but still have some questions. I was wondering can someone help explain the purpose of the interval being null. and how did this code work? how did it prevent the function starts
// Global variables
const time_el = document.querySelector('.watch .time');
const start_btn = document.getElementById('start');
const stop_btn = document.getElementById("stop");
const reset_btn = document.getElementById("reset");
let seconds = 0;
let interval = null;
// Event listeners
start_btn.addEventListener('click', start);
stop_btn.addEventListener("click", stop);
reset_btn.addEventListener("click", reset);
// Update the timer
function timer() {
seconds++;
// Format our time
let hrs = Math.floor(seconds / 3600);
let mins = Math.floor((seconds - (hrs * 3600)) / 60);
let secs = seconds % 60;
if (secs < 10) secs = '0' + secs;
if (mins < 10) mins = "0" + mins;
if (hrs < 10) hrs = "0" + hrs;
time_el.innerText = `${hrs}:${mins}:${secs}`;
}
function start() {
if (interval) {
return
}
interval = setInterval(timer, 1000);
}
function stop() {
clearInterval(interval);
interval = null;
}
function reset() {
stop();
seconds = 0;
time_el.innerText = '00:00:00';
}
<div class="watch">
<div class="time"></div>
</div>
<button id="start">start</button>
<button id="stop">stop</button>
<button id="reset">reset</button>
from running again when I clicked more than once?
function start () {
if (interval) {
return
}
interval = setInterval(timer, 1000);
}
I pasted the whole JS code to give a better context
In javascript null evaluates to false (falsy values): js-falsy, there are also values that evaluate to true (truthy values): js-truthy, so they initialize the variable interval to null so the code knows whether to start the timer, if it doesn't evaluate to false (falsy) the timer has been started and setInterval has been called, so it returns immediately on another click of the start button.
setInterval returns an Interval ID which is a unique identifier: setInterval, this is what is stored in interval on initial start button click, so on subsequent clicks, the variable interval evaluates to true (truthy).
Added a code snippet to demonstrate what I tried to describe in points 1 and 2.
let interval = null;
//Check to see if interval evaluates to false(falsy)
if(!interval){
console.log("interval evaluated to false(falsy)");
}
//set interval to the ID of call to setInterval()
interval = setInterval(() => {
console.log("setInterval() called and interval set to my ID");
}, 1000000);
//Check to see if interval evaluates to true(truthy)
if(interval){
console.log("setInterval ID: " + interval);
console.log("interval evaluated to true(truthy)");
}

how to check if the event is running

I want to create a simple eggtimer app. I created a timer and two buttons start and pause. However, since I'm a beginnner, I cannot work them right. When I hit the start button, the clock is running but if I hit the start button again, the setInterval is triggered again (which I don't want). Therefore, I used {once : true} with the event listener. But consequently when I use the pause button, I cannot resume the clock. I know I should store the event in a boolean, but I don't know how to do it correctly. Can you help me? I know the key things is setting the variable clockIsRunning in the right way. But how?
const startingMinutes = 25;
let time = startingMinutes * 60;
const startBtn = document.querySelector("#start-btn");
const pauseBtn = document.querySelector("#pause-btn");
const resetBtn = document.querySelector("reset-btn");
let interval;
let clockIsRunning = false;
// start button
startBtn.addEventListener("click", startCountdown, false);
const countdownEl = document.querySelector("#countdown");
function updateCountdown() {
const minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? "0" + seconds : seconds;
countdownEl.innerHTML = `${minutes}:${seconds}`;
time--;
clockIsRunning = true;
}
function startCountdown() {
if ((clockIsRunning = false)) {
interval = setInterval(updateCountdown, 1000);
}
}
// pause button
pauseBtn.addEventListener("click", function() {
clearInterval(interval);
});
<div id="display-container">
<div id="display-timer">
<p id="countdown">25:00</p>
</div>
<p id="display-logo">Focus</p>
</div>
<div id="buttons-container">
<button id="reset-btn">
<i class="fas fa-undo-alt"></i></ion-icon>Reset
</button>
<button id="start-btn"><i class="fas fa-play"></i></ion-icon>Start</button>
<button id="pause-btn"><i class="fas fa-pause"></i></ion-icon>Pause</button>
</div>
if...else take a condition, the code is executed if the boolean is true, not if false.
Knowing setInterval returns and integer (true) and clearInterval returns undefined (false), you can easily have a clock status by assign it to interval directly, thanks to #danh.
/* If clock is not running, start */
if(!interval) {
interval = setInterval(updateCountdown, 1000);
}
/* If clock is running, stop */
if(interval) {
interval = clearInterval(interval); // undefined
}
const startingMinutes = 25;
let time = startingMinutes * 60;
let interval;
const startBtn = document.querySelector("#start-btn");
const pauseBtn = document.querySelector("#pause-btn");
startBtn.addEventListener("click", startCountdown, false);
const countdownEl = document.querySelector("#countdown");
function updateCountdown() {
const minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? "0" + seconds : seconds;
countdownEl.innerHTML = `${minutes}:${seconds}`;
time--;
}
function startCountdown() {
if(!interval) {
updateCountdown();
interval = setInterval(updateCountdown, 1000);
}
}
// pause button
pauseBtn.addEventListener("click", function() {
if(interval) {
interval = clearInterval(interval);
}
});
<body>
<div id="display-container">
<div id="display-timer">
<p id="countdown">25:00</p>
</div>
</div>
<div id="buttons-container">
<button id="start-btn"><i class="fas fa-play"></i>Start/resume</button>
<button id="pause-btn"><i class="fas fa-pause"></i>Pause</button>
</div>
</body>
You have a few problems here. Your if statement in your startCountdown function assigns false to clockIsRunning, and so will always return false. What you should do is check for equality, i.e. use ==.
Then, if the clock isn't running, have the startCountdown function set the variable to true; this should not be done in the updateCountdown function, since this is run during the interval (i.e. after a second) and so could allow multiple intervals to be set if the Start button is clicked multiple times before the first interval elapses.
Also, in your event listener for the pause button, set clockIsRunning to false. Your code would look something like this:
// interval handler
function updateCountdown() {
const minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? "0" + seconds : seconds;
countdownEl.innerHTML = `${minutes}:${seconds}`;
time--;
}
// start button
function startCountdown() {
if ((clockIsRunning == false)) {
clockIsRunning = true;
interval = setInterval(updateCountdown, 1000);
}
}
// pause button
pauseBtn.addEventListener("click", function () {
clockIsRunning = false;
clearInterval(interval);
});

Why is the my function not being called in my SetInterval?

It's my first time using JS classes. I have a setInterval in a function but the function that is supposed to be repeating but I'm not sure why it's not.
class Stopwatch
{
constructor(isRunning, timer, timerTime)
{
this.isRunning = isRunning;
this.timer = timer;
this.timerTime = timerTime;
}
init()
{
// Put the element on the page with an id of start in a variable
// Do the same for the stop button and the reset button
const startButton = document.getElementById("start");
const stopButton = document.getElementById("stop");
const resetButton = document.getElementById("reset");
// Add an onclick handler to each of the buttons
// Use the functions startTimer, stopTimer and resetTimer
startButton.onclick = this.startTimer;
stopButton.onclick = this.stopTimer;
resetButton.onclick = this.resetTimer;
}
startTimer()
{
// if the timer is NOT running, start it
// call the function incrementTimer every second
// save the timer in a the timer variable
if(!this.isRunning)
{
this.isRunning = true;
this.timer = setInterval(this.incrementTimer, 1000);
}
}
incrementTimer()
{
// increment the timerTime
// calculate the number of minutes and seconds
this.timerTime++;
let minutes = Math.floor(this.timerTime / 60);
let seconds = this.timerTime % 60;
// write the minutes and seconds to the elements on the page
// use the function pad to make sure there's a leading 0 if necessary
document.getElementById("minutes").innerHTML = this.pad(this.minutes);
document.getElementById("seconds").innerHTML = this.pad(this.seconds);
}
pad(number)
{
// add a leading 0 if the number is < 10
if(number < 10)
number = "0" + number;
return number;
}
stopTimer()
{
// if the timer is running, stop it
if(this.isRunning)
{
isRunning = false;
timer = clearInterval(timer);
}
}
resetTimer()
{
// stop the timer
this.stopTimer();
// set the timerTime back to 0
this.timerTime = 0;
// write 00 to the elements on the page for minutes and seconds
document.getElementById("minutes").innerHTML = "00";
document.getElementById("seconds").innerHTML = "00";
}
}
let stopwatch = new Stopwatch(false, null, 0);
// When the page has finished loading, call the function init
window.onload = stopwatch.init();
When you set the onclick property of an element, the function you assign will always be called with the this value set to the element. Thus, the properties of this that you try to access will not be defined.
Instead of:
startButton.onclick = this.startTimer;
Use Function.prototype.bind to set the this value the function will be called with:
startButton.onclick = this.startTimer.bind(this);
Also, your code for incrementing the timer is incorrect:
let minutes = Math.floor(this.timerTime / 60);
let seconds = this.timerTime % 60;
document.getElementById("minutes").innerHTML = this.pad(this.minutes);
document.getElementById("seconds").innerHTML = this.pad(this.seconds);
this.minutes is undefined as you used let to declare minutes and seconds. Instead, just reference the variables using their names--i.e., minutes and seconds.
document.getElementById("minutes").innerHTML = this.pad(minutes);
document.getElementById("seconds").innerHTML = this.pad(seconds);
When you are stopping the timer, you forgot to add this in front of the property you were trying to access.
This:
if(this.isRunning){
isRunning = false;//isRunning is not defined as a local or global variables
timer = clearInterval(timer);//timer is not defined
}
Should be:
if(this.isRunning){
this.isRunning = false;
this.timer = clearInterval(this.timer);
}
Demo:
<button id="start">
Start
</button>
<button id="stop">
Stop
</button>
<button id="reset">
Reset
</button>
<span id="minutes"></span>:<span id="seconds"></span>
<script>
class Stopwatch
{
constructor(isRunning, timer, timerTime)
{
this.isRunning = isRunning;
this.timer = timer;
this.timerTime = timerTime;
}
init()
{
// Put the element on the page with an id of start in a variable
// Do the same for the stop button and the reset button
const startButton = document.getElementById("start");
const stopButton = document.getElementById("stop");
const resetButton = document.getElementById("reset");
// Add an onclick handler to each of the buttons
// Use the functions startTimer, stopTimer and resetTimer
startButton.onclick = this.startTimer.bind(this);
stopButton.onclick = this.stopTimer.bind(this);
resetButton.onclick = this.resetTimer.bind(this);
}
startTimer()
{
// if the timer is NOT running, start it
// call the function incrementTimer every second
// save the timer in a the timer variable
if(!this.isRunning)
{
this.isRunning = true;
this.timer = setInterval(this.incrementTimer.bind(this), 1000);
}
}
incrementTimer()
{
// increment the timerTime
// calculate the number of minutes and seconds
this.timerTime++;
let minutes = Math.floor(this.timerTime / 60);
let seconds = this.timerTime % 60;
// write the minutes and seconds to the elements on the page
// use the function pad to make sure there's a leading 0 if necessary
document.getElementById("minutes").innerHTML = this.pad(minutes);
document.getElementById("seconds").innerHTML = this.pad(seconds);
}
pad(number)
{
// add a leading 0 if the number is < 10
if(number < 10)
number = "0" + number;
return number;
}
stopTimer()
{
// if the timer is running, stop it
if(this.isRunning)
{
this.isRunning = false;
this.timer = clearInterval(this.timer);
}
}
resetTimer()
{
// stop the timer
this.stopTimer();
// set the timerTime back to 0
this.timerTime = 0;
// write 00 to the elements on the page for minutes and seconds
document.getElementById("minutes").innerHTML = "00";
document.getElementById("seconds").innerHTML = "00";
}
}
let stopwatch = new Stopwatch(false, null, 0);
// When the page has finished loading, call the function init
window.onload = stopwatch.init();
</script>

Countdown Timer not Stopping with clearInterval()

I'm having a problem get this countdown timer to stop at zero so the time won't show as a negative value. The console.log is getting called and works fine but for some reason the clearInterval() is not. This is driving me crazy and I'm close to quitting.
const timerContainer = document.getElementById('timerContainer');
const THREEMINUTES = 60 * 0.1;//5 seconds for testing
startTimer(THREEMINUTES, timerContainer);
function startTimer(duration, display) {
let start = Date.now();
let diff, min, sec;
let timer = () => {
diff = duration - (((Date.now() - start) / 1000) | 0);
//use bitwise to truncate the float
min = (diff / 60) | 0;
sec = (diff % 60) | 0;
min = min < 10 ? '0' + min : min;
sec = sec < 10 ? '0' + sec : sec;
display.textContent = min + ':' + sec;
if (diff <= 0) {
stopTimer();
submit.disabled = 'true';
};
};
//call timer immediately otherwise we wait a full second
timer();
setInterval(timer, 1000);
function stopTimer() {
clearInterval(timer);
console.log("time's up", diff);
};
}
<div id="timerContainer"></div>
You are not saving the result of setInterval(timer, 1000);
you should use this:
let timerId;
timer();
timerId = setInterval(timer, 1000);
function stopTimer() {
clearInterval(timerId);
console.log("time's up", diff)
};
As you might see, the result of setInterval is a number (object in node), and all you then need to do is pass that value to clearInterval thus we save the value in the variable timerId for reference.
Don't pass the function that you want stopped to clearInterval().
Pass a reference to the timer that you started, so you need to make sure that when you start a timer, you capture a reference to the ID that will be returned from it.
// Function that the timer will invoke
function callback(){
. . .
}
// Set up and initiate a timer and capture a reference to its unique ID
var timerID = setInterval(callback, 1000);
// When needed, cancel the timer by passing the reference to it
clearInterval(timerID);
The code is fixed make sure you fix your submit button code.
You should first assign the value of setInterval to a variable. That variable is used while calling clearInterval which infact clears the interval.
const timerContainer = document.getElementById('timerContainer');
const THREEMINUTES = 60 * 0.1;//5 seconds for testing
startTimer(THREEMINUTES, timerContainer);
var timer = null;
function startTimer(duration, display) {
let start = Date.now();
let diff, min, sec;
let timer = () => {
diff = duration - (((Date.now() - start) / 1000) | 0);
//use bitwise to truncate the float
min = (diff / 60) | 0;
sec = (diff % 60) | 0;
min = min < 10 ? '0' + min : min;
sec = sec < 10 ? '0' + sec : sec;
display.textContent = min + ':' + sec;
if (diff <= 0) {
stopTimer();
submit.disabled = 'true';
};
};
//call timer immediately otherwise we wait a full second
timer();
timer = setInterval(timer, 1000);
function stopTimer() {
clearInterval(timer);
console.log("time's up", diff);
};
}

Javascript - Interval not clearing

I'm making a game that has a timer in it.
What I'm trying to do is -- when the game starts via gameState.init(), the timer starts through timer.counter("start") -- but when the "restart" button is clicked, the timer stops and resets through timer.counter("reset").
The timer does reset back to 0, but it keeps counting and not getting cleared.
Appreciate any insight I can get. Thanks in advance!
var gameState = {
init: function(){
var difficultyLevel = document.querySelector('input[name="level"]:checked').value;
conditions.difficulty(difficultyLevel);
startFrame.classList.remove("active");
shuffleCards();
timer.counter("start");
display.moves(movesAllowed);
},
restart: function(){
startFrame.classList.add("active");
reset.allCards(cards);
shuffleCards();
timer.counter("reset");
matchCount = 0;
totalMoves = 0;
movesAllowed = 0;
timeAllowed = 0;
time = 0;
}
}
var timer = {
counter: function(status){
var clock = document.querySelector(".timer");
var incrementTime = setInterval(function(){
time++;
var minutes = Math.floor(time / 60);
var seconds = Math.floor(time % 60);
if(seconds < 10){
clock.innerText = minutes + ":0" + seconds;
} else {
clock.innerText = minutes + ":" + seconds;
}
}, 1000);
var stopTime = function(){
clearInterval(incrementTime);
}
if(status === "start"){
alert("counting");
}
if(status === "reset"){;
alert("reset");
stopTime();
}
}
}
Two issues:
The variable that holds the interval, incrementTime, is local to the counter function. Once the counter function ends, incrementTime gets garbage collected, because no reference to the interval remains anymore. You need the interval variable to be persistent instead.
You're setting a new interval every time counter is called. You should probably only set an interval when status is start, otherwise the old interval will continue running and won't be stoppable (reassigning the interval a setInterval is assigned to doesn't clear the interval):
let interval; // <---- Persistent
var timer = {
counter: function(status){
var clock = document.querySelector(".timer");
if (status === 'start') {
interval = setInterval(() => { // <---- Assign to persistent variable
time++;
var minutes = Math.floor(time / 60);
var seconds = Math.floor(time % 60);
if(seconds < 10){
clock.innerText = minutes + ":0" + seconds;
} else {
clock.innerText = minutes + ":" + seconds;
}
}, 1000);
alert("counting");
} else if(status === "reset"){
var stopTime = function(){
clearInterval(interval); // <---- Clear persistent variable
}
alert("reset");
stopTime();
}
}
}
(It would also be a bit more elegant for the stopTime and interval functions to be persistent, rather than being re-created every time they're needed; eg, you might assign them to properties of timer)

Categories

Resources