Can you restart a setInterval() after you've called a clearInterval()?

Hi, I’m trying to get a ‘start’ button functioning on my code. I managed to get the ’ stop reset ’ button functioning through calling clearInterval(), but now I’m stuck trying to figure out to start this little game back up. Can you restart a setInterval() after it has already been cleared? I’m still new to this, but here was my thought process:

  1. Take setInterval() and store in variable ‘game’.
  2. Select ‘start’ button store in variable ‘startG’.
  3. Create function startGame() set what I want to happen, and call ‘game()’ inside the function.
  4. Add event listener to ‘startG’ listen for click and call ‘startGame()’.

If anyone can help me out here it would be greatly appreciated.

Hey Jtog,

Congrats on the game. It’s fun to make stuff like this when starting out.

I feel your pain - it’s frustrating to get stuck. I’ll try to help, but I’m really just starting out myself.

Ok - when I open the console on your CodePen and I click on the start button, I get an error that ‘game’ is not a function. Maybe try making a function with name ‘game’ instead of an anonymous function inside of the setInterval.

Hmmm. I’ve seen it done to reset the game, simply reload the page. Like:
Reload

I hope this helps!

Hey Newman5 thanks for your response. The only thing is I need the setInterval as it’s controlling my timer. Is that what you mean? Replace the setInterval with a different function or do you mean to give the anonymous function a name and then call it at my startGame() function?

EDIT : This is what I just tried still couldn’t get it going.

Gave a name to anonymous function.

var game = setInterval(function gameInit(){
    loseBanner.style.display = 'none';
    winBanner.style.display = 'none';
    counter.style.display = 'block';
    increasing === true ? count++ : count = 0;
    counter.innerHTML = count;
    count === specifiedNumber ? increasing = false : increasing = true;
    if( count === specifiedNumber && score < 5) {
      losingBanner();
    } 
    if (count === specifiedNumber && score >= 5) {
      winningBanner();
    }
  }, 1000)

Called it at my startGame() function

  function startGame(){
      loseBanner.style.display = 'none';
      winBanner.style.display = 'none';
      increasing = true;
      count = 0;
      score = 0;
      gameInit();
  
  }

Called startGame function at startGame button/ event listener

startG.addEventListener('click', startGame);

Hey there. I think you can do what you want as follows. Try this in your browser console:

function gameClosure() {
    function game() {
        /* This is just an example, replace this with the body of gameInit() */
        console.log('The game is running')
    }
    
    var currentGame;
    
    return {
        start() {
            currentGame = setInterval(game, 1000)
        },
        stop() {
            clearInterval(currentGame)
        }
    }
}

var game = gameClosure()

game.start() // Then wait a bit...
game.stop() // And you can call these two functions over and over

This takes advantage of closures. If you’re not familiar, my two-minute explanation would be: If you declare a variable inside a function, normally, you’d expect everything else inside that function to have access to that variable, right? If you declare a function (an inner function) inside a function (an outer function), then everything inside the inner function has access to everything inside the outer function. This is still true even after the outer function has returned.

You should be able to assign game.start() and game.stop() to your event listeners this way and hopefully get what you’re looking for. Hope this works for you.

1 Like

Usual idiom in JS would be to use an object instead of a static closure. I actually prefer the static closure approach though. You get truly private members, and constructors are just functions, which makes them easier to use as HOFs. And by returning an object with methods, you get the best of both the functional and OOP worlds.

Common practice out there is still to use the built-in OO system though, and there’s advantages to that. But it’s handy that you can always write a static closure that returns an object if you want.

Hey bfce thank you for responding. I tried filling your code in on my codepen but it’s still not working. I’m guessing user error on my part. Am I missing something?

var counter = document.getElementById('counter');
//selects HTML '0'
var count = 0;
//sets count to '0'
var specifiedNumber = 7;
//max number on timer we want to reach
var scoreCount = document.getElementById('score');
var score = 0;
var increasing = true;

//   Start button      Stop/Reset buttons

var startG = document.getElementById('start');
startG.addEventListener('click', game.start);

var stopReset = document.getElementById('stop');
stopReset.addEventListener('click', game.stop);


//select Win and Lose Banners
var winBanner = document.getElementById('win');
var loseBanner = document.getElementById('lose');

function gameClosure() {
  function game() {
    loseBanner.style.display = 'none';
    winBanner.style.display = 'none';
    counter.style.display = 'block';
    increasing === true ? count++ : count = 0;
    counter.innerHTML = count;
    count === specifiedNumber ? increasing = false : increasing = true;
    if( count === specifiedNumber && score < 5) {
      losingBanner();
    } 
    if (count === specifiedNumber && score >= 5) {
      winningBanner();
    }
  }
  var currentGame;
  
  return {
    start(){
      currentGame = setInterval(game,1000)
    }, stop(){
      clearInterval(currentGame)
    }
  }
}

var game = gameClosure();

game.start();
game.stop();

  function stopResetGame(){
    loseBanner.style.display = 'none';
    winBanner.style.display = 'none';
    count = 0;
    score = 0;
    counter.innerHTML = count;
    clearInterval(game);
    
  }

  function startGame(){
      loseBanner.style.display = 'none';
      winBanner.style.display = 'none';
      increasing = true;
      count = 0;
      score = 0;
      
      
  }


  function losingBanner() {
      scoreCount.innerHTML = score;
      counter.style.display = 'none';
      loseBanner.style.display = 'block';
  }

  function winningBanner() {
    scoreCount.innerHTML = score;
    counter.style.display = 'none';
    winBanner.style.display = 'block';
  }

Looks like you’re assigning game.start and game.stop to your event listeners before those two methods are defined. Try moving your addEventListeners to some point in the code after you define game, I think that’ll work.

Awesome moving the event listeners worked! Thanks bfce.

  return {
    start(){
      currentGame = setInterval(game,1000)
    }, stop(){
      counter.innerHTML = count;
      count = 0;
      score = 0;
      clearInterval(currentGame)
    }
  }
}

All I had to do after that was set score and count back to zero.

2 Likes