'Trouble with setInterval() and clearInterval() while creating a pomodoro timer

I've been learning javascript for the last few months, so I am a rookie. Longtime reader, first time poster. The full code for what I'm working on is available here in this codepen

https://codepen.io/dconnenc/pen/yLpwrQO?editors=1011

I'm hitting a pretty bad wall.

My current problem is keeping my clock maintaining proper mm:ss format, and getting it to tick down to 00:00.

min = min < 10 ? "0" + min : min;
sec = sec < 10 ? "0" + sec : sec;

I had been using the above, but it became too fragile inside of the interval function and begin adding 0s at the start at every interval. I have a fix so that it stops adding zeroes, but now it only ticks down to 0:00, and never reaches 00:00.

sessionTime = sessionTime < 10 && !sessionTime.toString().startsWith("0") ? "0" + sessionTime : sessionTime;
sec = sec < 10 && !sessionTime.toString().startsWith("0") ? "0" + sec : sec;

I've got stop for the day, and take a break, but a larger snippet of the code is below, and of course the link to the full codepen is above.

function timer() {
    //ticks down timer
    if(sec > 0){
      sec--;
    } else if (sec == 0 && sessionTime == 0) {
      console.log("check");
      document.getElementById('time-left').textContent = breakTime + ":" + sec;
    } else if (sec == 0) {
      sessionTime--;
      sec = 59;
    } 
  
    //mm:ss format (started running into an error with the interval returning extra 0s)
    sessionTime = sessionTime < 10 && !sessionTime.toString().startsWith("0") ? "0" + sessionTime : sessionTime;
    sec = sec < 10 && !sessionTime.toString().startsWith("0") ? "0" + sec : sec;
    
    //updates display
    document.getElementById('time-left').textContent = sessionTime + ":" + sec; 
}


Solution 1:[1]

Try this with the min then with the seconds

if(sessionTime.toString().length === 1){
  if(sessionTime === 0){
     sessionTime = sessionTime;
    }else{
      sessionTime = "0"+sessionTime;
   }
 
}

Solution 2:[2]

This implements the expected behavior of your timer (Using a 500ms interval and 3 second "minutes") using a somewhat minimized example. Session Time is hardcoded to 3 minutes.

Mixing strings and integers in JavaScript can easily lead to coding issues like the ones you have experienced, especially when trying to use the + operator on mixed strings and integers. Best to avoid that in your control variables and lead with an obvious string when you're setting displays.

let oneSecond = 500;
let oneMinute = 3;

let sessionTime = 3;

var secondsRemaining;
var intervalId;

function reset() {
    console.log('check')
    clearInterval(intervalId);
    intervalId = 0
}

function start() {
    secondsRemaining = sessionTime * oneMinute;
    setTimeLeft()
    intervalId = setInterval(timer, oneSecond)
}

function timer() {
    if ( --secondsRemaining <= 0 ) {
       reset()
    }
    setTimeLeft()
}

function setTimeLeft() {
    document.getElementById('time-left').textContent = `${(''+ ~~(secondsRemaining / oneMinute)).padStart(2, '0')}:${(''+ secondsRemaining % oneMinute).padStart(2, '0')}`;
}

start()
<span id='time-left'></span>

This version handles multiple timers.

let oneSecond = 500;
let oneMinute = 3;

let sessionTime = 3;

function Timer(seconds, resetCallback, updateCallback, period) {
    this.s = seconds;
    this.p = period || oneSecond;
    this.callback = resetCallback || Function.prototype;
    this.update = updateCallback || Function.prototype;

    this.reset = function() {
      this.intervalId = clearInterval(this.intervalId)
      this.callback()
    }
    this.start = function() { this.update(this.s); this.intervalId = setInterval(this.timer.bind(this), [ this.p ]) }
    this.timer = function() { if (--this.s <= 0) this.reset(); this.update(this.s) }
}

function setTimeLeft(sec, id) {
  document.getElementById(id || 'time-left').textContent = `${(''+ ~~(sec / oneMinute)).padStart(2, '0')}:${(''+ sec % oneMinute).padStart(2, '0')}`;
}

document.addEventListener("DOMContentLoaded", function() {
  new Timer(sessionTime * oneMinute, () => console.log('check 1000ms'), setTimeLeft, 1000).start()
  new Timer(6 * oneMinute, () => console.log('check 500ms'), (s) => { setTimeLeft(s, 'time-left2')}, 500).start()
  new Timer(15 * oneMinute, () => console.log('check 300ms'), (s) => { setTimeLeft(s, 'time-left3')}, 200).start()
})
<span id='time-left'></span><br />
<span id='time-left2'></span><br />
<span id='time-left3'></span>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ingenious_Hans
Solution 2