I have a variable let second = 20 that i make 1 lower until it hits 0. When it hits 0 i want to stop running a part of my code but the variable second is always 20 when i use it because i make it lower in another scope. Sorry if my explenation is a bit unclear.
Here is the code:
votingEnd = document.querySelector(".imposters__voting");
imposters = document.querySelectorAll(".imposter");
let second = 20;
window.addEventListener("load", function () {
let myinterval;
myinterval = setInterval(function () {
second--;
if (second < 11) {
votingEnd.style.color = "red";
}
votingEnd.innerHTML = `Voting ends in: ${second}s`;
if (second == 0) {
clearInterval(myinterval);
votingEnd.innerHTML = `Voting has ended`;
}
}, 1000);
});
if (second > 0) {
//second is still 20 here because i lowered it in my function above. How can i solve this
for (let i = 0; i < imposters.length; i ) {
imposters[i].addEventListener("click", function () {
let count = 0;
while (count < imposters.length) {
imposters[count ].classList.remove("voted");
}
this.classList.add("voted");
});
}
}
CodePudding user response:
You could put the if (second > 0) inside the click function that way it will check for the most recent value of second instead of just once on load like so
for(let i = 0; i < imposters.length; i ){
imposters[i].addEventListener("click", function () {
if (second > 0) {
let count = 0;
while (count < imposters.length) {
imposters[count ].classList.remove("voted");
}
this.classList.add("voted");
}
});
CodePudding user response:
The problem has nothing to do with scope. It has to do with timing. That last part of your code only runs once, before the interval runs twenty times.
Here's the order of operations:
- Initialize
second
to20
. - Bind the countdown function to
window.onload
. (This does not run yet) - Check if
seconds
is greater than0
, and it is because the intervals haven't run yet. This is the only time this code ever runs. window.onload
is triggered, and your countdown begins- one second later,
seconds
is now19
19
seconds laterseconds
is not0
, and the interval is cleared.
So what you need to do is trigger your code in each iteration of the interval.
You want something closer to:
let second = 20;
window.addEventListener("load", function () {
const myinterval = setInterval(function () {
second--;
// other logic here...
if (second > 0) {
countdownTick(); // runs every second with the interval handler
}
if (second == 0) {
clearInterval(myinterval);
// cleanup
}
}, 1000);
});
function countdownTick() {
// Do the stuff you need to do each second here
}
CodePudding user response:
Your setInterval
runs every second. That does not mean that the rest of the code also runs every second. Which is why second is still 20 when the code gets to if (second > 0)
.
So you need to make sure that this part of your code runs every second as well. One solution would be to wrap that code inside a function which you call inside the interval, like this:
votingEnd = document.querySelector(".imposters__voting");
imposters = document.querySelectorAll(".imposter");
let second = 20;
window.addEventListener("load", function () {
let myinterval;
myinterval = setInterval(function () {
second--;
if (second < 11) {
votingEnd.style.color = "red";
}
votingEnd.innerHTML = `Voting ends in: ${second}s`;
if (second == 0) {
clearInterval(myinterval);
votingEnd.innerHTML = `Voting has ended`;
}
check();
}, 1000);
});
function check() {
if (second > 0) {
//second is still 20 here because i lowered it in my function above. How can i solve this
for (let i = 0; i < imposters.length; i ) {
imposters[i].addEventListener("click", function () {
let count = 0;
while (count < imposters.length) {
imposters[count ].classList.remove("voted");
}
this.classList.add("voted");
});
}
}
}