Home > Net >  How to execute setInterval at a later time in the code inside conditional statements in javascript?
How to execute setInterval at a later time in the code inside conditional statements in javascript?

Time:01-25

I am trying to change the background color of my html page, every 200 milliseconds using setInterval on event of click on the button id = 'button4'. And I want the changing of background color to stop when user clicks on the same button again.

The code for setInterval is executes when assigned to var x where as I want to execute it when a condition is satisfied inside the 'goCrazy' function when it is called. How can that be done?

The clearInterval is working fine and the changing of colors is stopped.

Below is my code.

var x = setInterval(()=> {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
    }, 200);

function goCrazy(){

    if (document.getElementById('button4').innerText == 'Go Crazy'){
        document.getElementById('button4').innerText = 'stop';
        x;
    }
    else{
        clearInterval(x);
        document.getElementById('button4').innerText = 'Go Crazy';
    }
}


function randomIntFromInterval(min, max) { // min and max included 
    return Math.floor(Math.random() * (max - min   1)   min)
  }
  

CodePudding user response:

You can extract the code inside setInterval into a named function, and call setInterval or clearInterval within goCrazy.

var x;

function goCrazy(){
    if (document.getElementById('button4').innerText == 'Go Crazy') {
        document.getElementById('button4').innerText = 'stop';
        x = setInterval(changeBackground, 200);
    }
    else {
        document.getElementById('button4').innerText = 'Go Crazy';
        if (x) clearInterval(x);
    } 
}

function changeBackground() {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
}

function randomIntFromInterval(min, max) { // min and max included 
    return Math.floor(Math.random() * (max - min   1)   min)
}

CodePudding user response:

Factalism's answer seems correct but we can take this further. If x, changeBackground and randomIntFromInterval aren't needed anywhere outside of goCrazy, they can all go inside. Yes even x can go inside if we return goCrazy from inside a closure, specifically an IIFE -- "immediately invoked function expression".

const goCrazy = (() => {
  let x;
  const button4 = document.getElementById('button4');
  
  return () => {
    if (button4).innerText == 'Go Crazy') {
        button4.innerText = 'stop';
        x = setInterval(changeBackground, 200);
    }
    else {
        button4.innerText = 'Go Crazy';
        if (x) clearInterval(x);
    }     
  }

  function changeBackground() {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
  }
  
  function randomIntFromInterval(min, max) { // min and max included 
      return Math.floor(Math.random() * (max - min   1)   min)
  }
})()

CodePudding user response:

The OP firstly needs to make the background changing function which is supposed to be run within an interval an addressable function by e.g. implementing it as function statement.

Second, the OP needs to keep track of a running/halted interval. One could achieve this by a single event handler which is aware of an own this context where one could bind at least a timeId to it and maybe even some additional button-related text-data.

The implementation of the handler function which gets registered with a button's 'click' event-listener then is very straightforward.

Depending on the null value comparison of the bound timerId one detects an either 'running' or 'halted' interval which makes it easy to continue with either clearing the running interval or starting a new interval (including the button's text-toggle).

function getRandomValue(min, max) {
  return Math.floor(Math.random() * (max - min   1)   min);
}
function setRandomBackgroundColor() {
  document.body.style.backgroundColor =
    `rgb(${getRandomValue(0, 255)},${getRandomValue(0, 255)},${getRandomValue(0, 255)})`;
}

function toggleBackgroundBehaviorFromBoundState({ currentTarget: elmBtn }) {
  let toggleState;

  if ((this.timerId ?? null) !== null) {

    clearInterval(this.timerId);

    // explicitly nullify value due to the above `null` comparison.
    this.timerId = null;

    toggleState = 'halted';
  } else {
    this.timerId = setInterval(setRandomBackgroundColor, 100);

    toggleState = 'running';
  }
  elmBtn.textContent = this?.buttonCopy?.[toggleState];
}

function main() {
  document
    .querySelector('#button4')
    .addEventListener(
      'click',
      toggleBackgroundBehaviorFromBoundState.bind({
        buttonCopy: {
          running: 'Stop',
          halted: 'Go Crazy',
        },
        timerId: null,
      })
    );
}
main();
<button id="button4">Go Crazy</button>

  • Related