Wayne Bunch Wayne Bunch - 7 days ago 4
Javascript Question

Javascript - Pausing an IIFE output that has setTimeout and displays min/sec - Pomodoro Clock

I have two functions that display minutes and seconds. Inside the functions I'm using an IIFE with a setTimeout to calculate the time. After getting this, having a hard time figuring out how I could pause the display if pause button is clicked.

The timer works fine and displays correctly.

I realize this is probably not a good way to do it, but I spent so much time (trying to learn how to use IIFE) that I don't want to give up. If I have to, then I will scratch it.

Update - This timer will be getting input from the user. It might be 25 minutes. I want it to start counting down from there until it reaches 0, and the user able to pause at anytime.

let convertToSeconds = document.getElementById('timeValue').value * 60;
let seconds = 60;

function secondsCounter(time) {
// let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
})(i);
}
}

function counter() {
for (let i = convertToSeconds; i > 0; i--) {
(function(minutes) {
setTimeout(function() {
let remaining = Math.floor((convertToSeconds - minutes) / 60);
document.getElementById('displayMinutes').innerHTML = remaining;
console.log(remaining);
}, i * 1000);

setTimeout(function() {
secondsCounter(seconds);
}, i * 60000);

})(i);
}

secondsCounter(seconds);

}


I've tried a couple of things.


  1. Using a flag and if statement around
    document.getElementById('displaySeconds').innerHTML = remaining;
    so if my pause button is clicked, the flag changes, and another setTimeout (10 minutes) is triggered. Doesn't stop the countdown on the DOM, it keeps going. I just wanted to see some reaction, but nothing happened. Something like:

    function secondsCounter(time) {
    let flag = document.getElementById('pauseButton').value;

    for (let i = seconds; i > 0; i--) {
    (function(x) {
    setTimeout(function() {
    let remaining = seconds - x;

    if (flag === 'yes') {
    document.getElementById('displaySeconds').innerHTML = remaining;
    console.log(remaining);
    } else {
    setTimeout(function() {
    console.log(remaining);
    }, 10000);
    }

    }, i * 1000);
    })(i);
    }
    }

  2. Using a setInterval and clearInterval that didn't do anything.



Is this possible? Not sure where else to look. Thank you

Answer

You can't stop/pause a setTimeout or clearTimeout without making a reference to the timer, storing it and then calling clearTimeout(timer) or clearInterval(timer).

So, instead of: setTimeout(someFunciton)

You need: timer = setTimeout(someFunciton)

And, the timer variable needs to be declared in a scope that is accessible to all functions that will use it.

See setTimeout() for details.

Without a reference to the timer, you will not be able to stop it and that's caused you to go on a wild goose chase for other ways to do it, which is overthinking what you actually need.

In the end, I think you should just have one function that does all the counting down so that you only have one timer to worry about.

Lastly, you can use the JavaScript Date object and its get / set Hours, Minutes and Seconds methods to take care of the reverse counting for you.

(function() {
      // Ask user for a time to start counting down from.
      var countdown = prompt("How much time do you want to put on the clock? (hh:mm:ss)");
  
      // Take that string and split it into the HH, MM and SS stored in an array   
      var countdownArray = countdown.split(":")      
  
      // Extract the individual pieces of the array and convert to numbers:
      var hh = parseInt(countdownArray[0],10);
      var mm = parseInt(countdownArray[1],10);
      var ss = parseInt(countdownArray[2],10); 
  
      // Make a new date and set it to the countdown value
      var countdownTime = new Date();
      countdownTime.setHours(hh, mm, ss);
  
      // DOM object variables
      var clock = null,  btnStart = null, btnStop = null;

      // Make a reference to the timer that will represent the running clock function
      var timer = null;

      window.addEventListener("DOMContentLoaded", function () {

        // Make a cache variable to the DOM element we'll want to use more than once:
        clock = document.getElementById("clock");
        btnStart = document.getElementById("btnStart");
        btnStop = document.getElementById("btnStop");

        // Wire up the buttons
        btnStart.addEventListener("click", startClock);
        btnStop.addEventListener("click", stopClock);

        // Start the clock
        startClock();

      });

      function startClock() {
        // Make sure to stop any previously running timers so that only
        // one will ever be running
        clearTimeout(timer);
        
        // Get the current time and display
        console.log(countdownTime.getSeconds());
        countdownTime.setSeconds(countdownTime.getSeconds() - 1);
        clock.innerHTML = countdownTime.toLocaleTimeString().replace(" AM", "");


        // Have this function call itself, recursively every 900ms
        timer = setTimeout(startClock, 900);
      }
      
      function stopClock() {
        // Have this function call itself, recursively every 900ms
        clearTimeout(timer);
      }

 }());
<div id="clock"></div>
<button id="btnStart">Start Clock</button>
<button id="btnStop">Stop Clock</button>