2

I have this web page with a textarea and 3 buttons. The textarea receives a number. The first button starts the coutdown from the number to 0, with a delayed output (one number per second, so if N is 10 it'll take 10 seconds). The second button pauses the countdown, and the third button resumes it (without starting over). Pressing the first button at any time during the execution restarts the coutdown with whatever number is in the textarea. This is the code I have so far:

<!DOCTYPE html>
<html>
    <body>
        <h2>Insert a number:</h2>
        <textarea id="input"></textarea>
        <br/>
        <button id="start" onclick="begin()">BEGIN</button>
        <button id="pause" onclick="pause()">PAUSE</button>
        <button id="resume" onclick="resume()">RESUME</button>
        <h1 id="result"></h1>
        <script>
            var isCounting=true,
                input=document.getElementById("input"),
                countSec;
            function begin() {
                countSec=input.value;
                if (isNaN(countSec)) alert("NaN");
                count();
            }
            function pause() {
                isCounting=false;
            }
            function resume() {
                isCounting=true;
                count();
            }
            function count() {
                var i,
                    bck=countSec;
                for (i=0; i<=bck; i++) {
                    document.getElementById("result").innerHTML=countSec;
                    countSec--;
                }
            }
        </script>
    </body>
</html>

Is there a way to stop the execution for 1 second after countSec--? I've been trying for 2 hours to do something with Date objects and setTimeout but I just can't figure out how to pause after every for iteration

7 Answers 7

1

Here is an option:

    <script>
        var input=document.getElementById("input"),
            countSec,
            timer = null;

        function begin() {
            countSec=input.value;
            if (isNaN(countSec)) alert("NaN");
            if( timer === null ) {
                timer = setTimeout( count, 1000 );
            }
        }

        function pause() {
            clearTimeout( timer );
            timer = null;
        }

        function resume() {
            if( timer === null ) {
                timer = setTimeout( count, 1000 );
            }
        }

        function count() {
            if( countSec > 0 ) {
                countSec--;
            }

            document.getElementById("result").innerHTML = countSec;

            if( countSec > 0 ) {
                timer = setTimeout( count, 1000 );
            }
        }
    </script>

As begin is called it sets a timer on count after 1 second.

When later count is invoked it decreases the counter, updates the html and schedules itself to be recalled after 1 second with setTimeout() (unless -of course- the counter reached zero)

The scheduled task is stored into timer so it can be canceled with clearTimeout() (see pause())

To resume the countdown just call count() again.

timer is set to null when the counter is not running and is checked before starting it to ensure only one counter is running.

Sign up to request clarification or add additional context in comments.

4 Comments

just a small thing, your code does countSec-- before outputting the first number, so I had to change the first line of the begin function with countSec=parseInt(input.value)+1
yes, your're right! You could also use setTimeout on begin. As you already figured out a fix I'll edit the answer with this second one.
Also, different istances of the count() function start running at the same time if you press the begin button twice, and as a result the countdown is faster than normal. Or at least that's what I believe is happening, I'm still kinda new to setInterval and setTimeout. Anyways, I added clearTimeout(timer); under countSec-- in the first if block in the count function and it (magically?) works
sure... this can be fixed by setting timer to null when the timer is not running and start it again only if timer===null; will update in a moment
1

If you need a delay between each subtraction of countSec, then I recommend you use the setInterval function. I've modified your code as follows:

var isCounting=true,
    input=document.getElementById("input"),
    countSec
    interval;
function begin() {
    countSec=input.value;
    if (isNaN(countSec)) alert("NaN");
    count();
}
function pause() {
    isCounting=false;
    clearInterval(interval);
}
function resume() {
    isCounting=true;
    count();
}
function count() {
    var i,
        bck=countSec;

    document.getElementById("result").innerHTML=bck;               

    interval = setInterval(function() {
        countSec--;
        document.getElementById("result").innerHTML=countSec;               
    }, 1000);
}

Specifically, I created a global interval variable, which will keep a reference to the interval. I set the interval in count(), and then I update the #result ID at every tick of the interval (which has a delay of 1000ms). To pause, I clear the interval. I left a lot of your code in tact even though some of it isn't being used (like isCounting);

Here's the code in action: https://jsfiddle.net/exex7jh0/

Comments

1

This sounds like the perfect scenario to implement Javascript's built-in asynchronous interval operations.

Your timer should center around setInterval ( https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval ). Basically, you'll set up your interval to fire every second, which will increment your counter.

To pause your countdown, you'll want to use clearInterval ( https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval ). You can also use the intervalID to determine whether the setInterval timer is running or not.

These building blocks should get you going. If you require more information, just ask.

Comments

1

I think most of the solutions have already answered your question. It is a better idea to involve interval operations in your solution as that is more apt and JS already provides it.

  • Also a better idea to separate out your JS and HTML. (By avoiding inline event handlers)

HTML

<h2>Insert a number:</h2>
<textarea id="input"></textarea>
<br/>
<button id="start">BEGIN</button>
<button id="pause">PAUSE</button>
<button id="resume">RESUME</button>
<h1 id="result"></h1>

JS

// Bind the click events
document.getElementById('start').addEventListener('click', begin);
document.getElementById('pause').addEventListener('click', pause);
document.getElementById('resume').addEventListener('click', resume);

var input = document.getElementById("input");
var countSec;
var timer;

function begin() {
  debugger;
  countSec = input.value;
  if (isNaN(countSec)) alert("NaN");
  count();
  enableTimer();
}

function pause() {
  clearInterval(timer);
}

function resume() {
  enableTimer();
}

function count() {
  if (countSec >= 0) {
    document.getElementById("result").innerHTML = countSec;
  } else {
    clearInterval(timer);
  }
  countSec--;
}

// enable the timer again 
function enableTimer() {
   timer = setInterval(function() {
      count();
    }, 1000);
}

JsFiddle

Comments

1

What you want is for your count function to contain a self invoking timer, like this:

var timer;

function count() {
    var result = document.getElementById("result");

    step();

    function step() {
        result.innerHTML=countSec;
        countSec--;
        if (countSec > 0) {
            timer = setTimeout(step, 1000);
        }
    }
}

But know that the timeout doesn't really count 1000ms. If you want to be accurate you'll have to compare to the time where it all began. and lower the interval:

var timer,
    start,
    moment,
    input = document.getElementById("input"),
    result = document.getElementById("result");

function begin() {
    var from = ((parseInt(input.value) + 1) * 1000);
    start = Date.now() + from;
    setTimeout(count, 40);
}

function pause() {
    clearTimeout(timer);
}

function resume() {
    start = Date.now() + (moment * 1000);
    count();
}

function count() {
    moment = parseInt((start - Date.now()) / 1000);
    result.innerHTML = moment;
    if (moment > 0) {
        timer = setTimeout(count, 200);
    }
}

Comments

0

You could use setInterval, an intervalID and clearInterval, when the count reaches zero.

var isCounting = true,
    input = document.getElementById("input"),
    countSec,
    intervalID;

function begin() {
    countSec = +input.value;
    if (isNaN(countSec)) {
        alert("NaN");
        return;
    }
    document.getElementById("result").innerHTML = countSec;
    intervalID = setInterval(count, 1000);
}

function pause() {
    isCounting = false;
}

function resume() {
    isCounting = true;
}

function count() {
    if (countSec === 0) {
        clearInterval(intervalID);
        return;
    }
    if (isCounting) {
        countSec--;
        document.getElementById("result").innerHTML = countSec;
    }
}
<h2>Insert a number:</h2>
<textarea id="input"></textarea><br/>
<button id="start" onclick="begin()">BEGIN</button>
<button id="pause" onclick="pause()">PAUSE</button>
<button id="resume" onclick="resume()">RESUME</button>
<h1 id="result"></h1>

Comments

0

Heres another solution

<!DOCTYPE html>
<html>

  <body>
    <h2>Insert a number:</h2>
    <textarea id="input"></textarea>
    <br/>
    <button id="start" onclick="begin()">BEGIN</button>
    <button id="pause" onclick="pause()">PAUSE</button>
    <button id="resume" onclick="resume()">RESUME</button>
    <h1 id="result"></h1>
    <script>
      let isCounting = true;
      let input = document.getElementById("input");
      let countSec = 0;
      let countDownInterval = false;

      function begin() {
        countSec = input.value;
        if (isNaN(countSec)) alert("NaN");
        count();
      }

      function pause() {
        isCounting = false;
      }

      function resume() {
        isCounting = true;
      }

      function count() {
        // Let's check we're doing a restart 
        if (countDownInterval) {
          clearInterval(countDownInterval);
        }

        countDownInterval = setInterval(function() {
          if (isCounting) {
            document.getElementById("result").innerHTML = countSec;
            countSec -= 1;
            // Times up ??
            if (countSec == -1) {
              clearInterval(countDownInterval);
              countDownInterval = null;
            }
          }
        }, 1000);
      }

    </script>
  </body>

</html>

jsfiddle

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.