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>