Search code examples
javascriptcountdowngetter

JS getter and intervals not working properly in countdown timer


Trying to understand how the theory works, the idea is to create a countdown with minutes and seconds, with a btn to start/continue and another to pause.

It needs to subtract 1 min the first time it starts. (speed and number of secs changed so it goes faster, it should work the same anyway) From what I've read, this can be done with a getter inside an object to detect if the time is = to initial time and if so, do the change. In this case, how do I change the original var min value from 3 to 2 instead of creating a new var inside the object?

It partially works, now the problem is: After pressing Start, if you press Pause when it begins the countdown, then press Start again to continue, it shows undefined instead of 2. Why is the value lost? How to prevent this? Also, after the pause and resume, the intervals for min and sec are out of sync.

This 1 min change also causes the when the last minute is reached, the seconds jump to 0 instead of going down one by one until it gets to 0.

This whole countdown can be rebuilt in a more elegant way, but I just don't understand the logic behind why is it not working as it is now and have no idea how to fix this.

Any help would be much appreciated. Thanks!

var initialmin = 3;
var min = 3;
var sec = 20;

//Display initial time
document.getElementById("min").innerHTML = initialmin;
if (sec = 20) {
  document.getElementById("sec").innerHTML = "00";
}

//subtract 1 min when countdown starts the first time
//How to change value of var min instead of creating timeleft.minleft?
timeleft = {
  get minleft() {
    if ((min == initialmin) && (sec == 20)) {
      console.log("first start: rest 1 min");
      return min = min - 1;
    }
  }
} //end timeleft


function start() {
  //Change 00 seconds placeholder with current seconds
  document.getElementById("sec").innerHTML = sec;

  //show 1 less minute than initial min
  document.getElementById("min").innerHTML = timeleft.minleft;

  //subtract minutes every 20sec
  subtractminutes = setInterval(function() {

    min -= 1;
    document.getElementById("min").textContent = min;
    console.log(min);

    //when reach 0 minutes, stop subtracting minutes
    if (min == 0) {
      console.log("min done");
      clearInterval(subtractminutes);

    }
  }, 2000);

  subtractseconds = setInterval(function() {
    //restart 20sec countdown if there are still minutes left
    sec--;
    document.getElementById("sec").textContent = sec;
    if ((min >= 1) && (sec == 0))
      sec += 20;

    //when last min is reached, stop counting seconds once reached 0
    if ((min == 0) && (sec == 0)) {
      console.log("sec done");
      clearInterval(subtractseconds);
    }

  }, 100);

}

function stop() {
  clearInterval(subtractseconds);
  clearInterval(subtractminutes);
}
<div id="controls">
  <button id="start" onclick="start()">Start</button>
  <button id="stop" onclick="stop()">Stop</button>
</div>

<p id="min"></p>
<p id="sec"></p>


Solution

  • When you restart the timer, your condition in the getter method is false, and it return undefined by default.

    timeleft = {
      get minleft() {
        if ((min == initialmin) && (sec == 20)) { // condition here is false
          console.log("first start: rest 1 min");
          return min = min - 1;
        }
        // return undefined by default
      }
    }