Question from a JS learner.
I'm making a countdown from 10 to 0 for this game like project. However, the countdown starts without a click event. I want it to start as an event listener but I don't know how to stop this function from running.
<div class="display-buttons-container">
<div class="display">10</div>
<button id="arm">Arm</button>
<button id="disarm">Disarm</button>
</div>
const btnArm = document.querySelector("#arm");
const btnDisarm = document.querySelector("#disarm");
const countdown = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
const countdownDisplay = document.querySelector(".display");
let i = 0;
btnArm.addEventListener("click", countdownFunction());
function countdownFunction() {
countdownDisplay.innerHTML = countdown[i];
++i;
if (i > 10) countdownDisplay.innerHTML = 0;
}
setInterval(countdownFunction, 1000);
You need to remove the parentheses after countdownFunction to stop it from running the function immediately
You need to save the interval id returned from setInterval
you can call clearInterval and pass the interval id as the parameter and it will stop the interval
const btnArm = document.querySelector("#arm");
const btnDisarm = document.querySelector("#disarm");
const countdown = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
const countdownDisplay = document.querySelector(".display");
let i = 0;
let intervalId
function countdownFunction() {
countdownDisplay.innerHTML = countdown[i];
++i;
if (i > 10) countdownDisplay.innerHTML = 0;
}
btnArm.addEventListener("click", () => {
if (intervalId) return
intervalId = setInterval(countdownFunction, 1000)
});
btnDisarm.addEventListener("click", () => clearInterval(intervalId))
<div class="display-buttons-container">
<div class="display">10</div>
<button id="arm">Arm</button>
<button id="disarm">Disarm</button>
</div>
Here the setInterval is not inside the countdownFunction function thats the reason it running without any click event.
and to stop the timer you can use clearInterval(intervalID) which is used to clear a timer that is set with the setInterval() method.
const btnArm = document.querySelector("#arm");
const btnDisarm = document.querySelector("#disarm");
// no need of this array you can use a single variable instead
// const countdown = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
let count = 10;
let intervalID;
const countdownDisplay = document.querySelector(".display");
function startTimer() {
count = 10;
// clearing timer in case user wants to restart the timer
if (intervalID) {
clearInterval(intervalID); // clearing timer
intervalID = undefined; // resetting intervalID
}
// intervalID will be used to clear the timer
intervalID = setInterval(() => {
if (count === 0 && intervalID) {
clearInterval(intervalID); // clearing timer
intervalID = undefined; // resetting intervalID
}
countdownDisplay.innerHTML = count;
--count;
}, 1000);
}
function stopTimer() {
// clearing timer if intervalID is defined i.e. if any timer is in running state.
if (intervalID) {
clearInterval(intervalID); // clearing timer
intervalID = undefined; // resetting intervalID
}
}
<div class="display-buttons-container">
<div class="display">10</div>
<button id="arm" onclick="startTimer()">Arm</button>
<button id="disarm" onclick="stopTimer()">Disarm</button>
</div>
I generally prefer setTimeout for this kind of operation. That said the key to this is to declare a variable that can hold the timer that both the arm/disarm functions can use to either set the timer or clear the timer respectively.
btnArm.addEventListener("click", countdownFunction()); assigns the returned value of calling the function to the listener. Unless you're returning a function you don't want to do this. btnArm.addEventListener("click", countdownFunction); assigns a reference to the function instead.
I've made all the elements identifiable by class for consistency.
Added new function that clears the timer.
Removed the requirement for an array - you can just set a default for the current count.
Used textContent rather than innerHTML.
// Cache the elements
const arm = document.querySelector('.arm');
const disarm = document.querySelector('.disarm');
const display = document.querySelector('.display');
// Set up the listeners
arm.addEventListener('click', start);
disarm.addEventListener('click', stop);
// Declare the timer variable
let timer;
function start() {
// When `start` is called it immediately calls
// `loop` with default count of 10
function loop(count = 10) {
// If count > 0 display the count, and call loop
// again with a reduced count
if (count > 0) {
display.textContent = count;
timer = setTimeout(loop, 1000, --count);
// Otherwise "Boom!"
} else {
display.textContent = '💥 Boom! 💥';
}
}
// Call the loop for the first time
loop();
}
// If "disarm" is called clear the timer
function stop() {
clearTimeout(timer);
display.textContent = 'Disarmed';
}
button { font-size: 1.2rem; padding: 0.4em 0.8em; border: 1px solid #dfdfdf; border-radius: 5px; margin: 0.5em 0.25em; }
button:hover { cursor: pointer; border: 1px solid #454545; }
.arm { background-color: salmon; }
.disarm { background-color: lightgreen; }
.display { margin: 1em 0.25em; font-size: 1.6rem; }
<button class="arm">Arm</button>
<button class="disarm">Disarm</button>
<div class="display"></div>