-1

I'm trying to make a simple javascript counter.

Basically, I'm getting an integer value from a user by input and I want to count descending from that value to 0.

So I coded this:

let inputCounter = document.querySelector("#input-counter");
let startBox = document.querySelector(".start-box");
let startCounter = document.querySelector("#start-counter");
let errorMessage = document.querySelector("#error-message");
let timerCircle = document.querySelector(".c100");
let timeSpan = document.querySelector(".c100 > span");

startCounter.addEventListener('click', function() {
  let seconds = inputCounter.value;
  if (isNaN(seconds)) {
    errorMessage.textContent = "Not an integer value";
    errorMessage.classList.add("active");
  } else {
    errorMessage.classList.remove("active");
    timerCircle.style.display = "block";
    startBox.style.display = "none";
    timeSpan.textContent = seconds;

    let timerId = setInterval(() => {
      seconds -= 1;
      if (seconds < 0) {
        clearInterval(timerId);
      }

      timeSpan.textContent = seconds;
    }, 1000);
  }
});
<div class="container">
  <div class="start-box">
    <input type="text" id="input-counter" placeholder="type your value in seconds">
    <button id="start-counter">Start</button>
    <div id="error-message"></div>
  </div>
  <div class="c100 p50">
    <span></span>
    <div class="slice">
      <div class="bar"></div>
      <div class="fill"></div>
    </div>
  </div>
</div>

So this works fine and properly counts down from that custom entered number but the only problem here is that it goes to -1, -2, -3 and etc.

So that is why I tried determining timerId to the setInterval function and then checking this condition:

if(seconds < 0){
    clearInterval(timerId);
}

However it does not clear the interval and still shows Negative numbers...

So what's going wrong here? How can I properly clear the interval when it comes to 0?

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
Pouya
  • 114
  • 1
  • 8
  • 36
  • 3
    i tried your code and it stops at -1. i think `if(seconds < 1)` should fix it. – Layhout Aug 01 '22 at 08:02
  • I can't reproduce the problem. It gets to `-1`, successfully clears the interval, then `timeSpan.textContent = seconds;` assigns the `-1`, **then stops**. It doen't go to -2.. If you don't want to assign the -1 then `return` inside the `if` or stop the loop sooner. `clearInterval` stops the function running *again*, it doesn't abort the current execution of it. – Quentin Aug 01 '22 at 08:04
  • Your issue is in the condition, you need to have `seconds===0` as you are checking for `seconds<0` for triggering `clearInterval` which will clear the next successive interval and not the current iteration and hence `timeSpan.textContent` gets the value of -1 due to your condition. – GodWin1100 Aug 01 '22 at 08:04
  • @GodWin Great, you may add that as the answer – Pouya Aug 01 '22 at 08:08
  • Glad it help you clarify the bug. You can also `return` in `if` block or adapt any other method according to the case. – GodWin1100 Aug 01 '22 at 08:09

3 Answers3

0

Try this code:

    let seconds = 10
    let timerId = setInterval(() => {
      
      if (seconds <= 0) {
        clearInterval(timerId);
      }

      console.log(seconds);
    seconds -= 1;
    }, 1000);
0

Your clearInterval implementation works, but it is missing a return statement following the clear. So it clears the interval correctly (it won't run the setTimeout callback again) but the current execution of the callback continues, so it goes past the if statement and sets -1 in the label anyway. The return statement, halts the execution of that callback when you reach your base case, and leaves the label set to 0.

You could also re-arrange the code to set the label above the if statement, and change the condition to if (seconds === 0), so then following the clear and return, your seconds variable remains at 0, instead of -1.

let inputCounter = document.querySelector("#input-counter");
let startBox = document.querySelector(".start-box");
let startCounter = document.querySelector("#start-counter");
let errorMessage = document.querySelector("#error-message");
let timerCircle = document.querySelector(".c100");
let timeSpan = document.querySelector(".c100 > span");

startCounter.addEventListener('click', function() {
  let seconds = inputCounter.value;
  if (isNaN(seconds)) {
    errorMessage.textContent = "Not an integer value";
    errorMessage.classList.add("active");
  } else {
    errorMessage.classList.remove("active");
    timerCircle.style.display = "block";
    startBox.style.display = "none";
    timeSpan.textContent = seconds;

    let timerId = setInterval(() => {
      seconds -= 1;
      if (seconds < 0) {
        clearInterval(timerId);
        return; // THIS IS WHAT WAS MISSING
      }

      timeSpan.textContent = seconds;
    }, 1000);
  }
});
<div class="container">
  <div class="start-box">
    <input type="text" id="input-counter" placeholder="type your value in seconds">
    <button id="start-counter">Start</button>
    <div id="error-message"></div>
  </div>
  <div class="c100 p50">
    <span></span>
    <div class="slice">
      <div class="bar"></div>
      <div class="fill"></div>
    </div>
  </div>
</div>
Daniel Wardin
  • 1,840
  • 26
  • 48
0

If you stop when < 0, it will check:

  • 2, reduce, its now 1, its < 0? NO, so go again
  • 1, reduce, its now 0, its < 0? NO, so go again
  • 1, reduce, its now -1, its < 0? yes, stop: result -1

You can stop in < 1 or <= 0.
console.log(seconds) // 0

Additionally, working with timeout and numeric variables is not so accurate (depends on instabilities in processing).

I suggest saving the start time, and calculating the difference every second.

If the PC freezes for 3 seconds, when it starts up again, 3 seconds have passed and not just 1.


let inputCounter = document.querySelector("#input-counter");
let startBox = document.querySelector(".start-box");
let startCounter = document.querySelector("#start-counter");
let errorMessage = document.querySelector("#error-message");
let timerCircle = document.querySelector(".c100");
let timeSpan = document.querySelector(".c100 > span");

startCounter.addEventListener('click', function() {
  let seconds = inputCounter.value;
  if (isNaN(seconds)) {
    errorMessage.textContent = "Not an integer value";
    errorMessage.classList.add("active");
  } else {
    errorMessage.classList.remove("active");
    timerCircle.style.display = "block";
    startBox.style.display = "none";
    timeSpan.textContent = seconds;

    let timerId = setInterval(() => {
console.log({seconds})
      seconds -= 1;
      if (seconds < 1) {
        clearInterval(timerId);
      }

      timeSpan.textContent = seconds;
    }, 1000);
  }
});
<div class="container">
  <div class="start-box">
    <input type="text" id="input-counter" placeholder="type your value in seconds">
    <button id="start-counter">Start</button>
    <div id="error-message"></div>
  </div>
  <div class="c100 p50">
    <span></span>
    <div class="slice">
      <div class="bar"></div>
      <div class="fill"></div>
    </div>
  </div>
</div>
Emanuel
  • 2,603
  • 22
  • 24