Maccles
Maccles

Reputation: 131

Change colour on every iteration of forEach loop in javascript?

I have a function that changes the colour of an element briefly, then changes it back to the original colour. Depending on the level you're at (it's a puzzle game), a forEach loop then runs this function for a a certain number of times (more at higher levels). Currently the colour the element changes to is whatever I've manually input into the code. I'm trying to find a way to changing that colour every time the forEach runs the function.

For example, say you are on the first round and the forEach runs three times, the element will flash red-white, red-white, red-white. What I need is for it to flash red-white, blue-white, pink-white. It also needs to loop back to the beginning of the array when it runs out of colours. For example at a higher level the forEach might run 6 times, so the iteration over the colours array will have to go back to the start once. Here's the code:

function showCircle(item, j, x) {
  setTimeout(function () {
let x = 0;
let colors = ['blue','pink','green']
let color = colors[x];
    var num = initArray[j];
    var element = document.getElementById(num)
    element.classList.add(`cell-glow-${color}`)
    window.setTimeout(function () {
      element.classList.remove(`cell-glow-${color}`)
    }, 400);
    j++;
    x++
    console.log(color)
  }, speed() * j);
};

function showEachCircle(captureUserClicks) {
  initArray.forEach(showCircle);
  }

Clearly what's happening above is that the showCircle function is zero-ing x each time, so it gets stuck on the first iteration. But I'm not sure where I should be putting those variables to make it iterate properly. Plus I haven't even begun to get my head around forcing the array to go back to the beginning.

Any ideas? Thank you!

Upvotes: 2

Views: 2032

Answers (2)

clod9353
clod9353

Reputation: 2002

This is how I would do it:

  • To avoid x=0 being executed every time you call the function, we're going to put it outside of it.

  • To iterate over the array of colors we will take advantage of the modulo operator:

     `x = (x+1)%3`
    

    This, instead of x++ will get the values 0, 1, 2 over and over again.

  • array.forEach() would call the function multiple times without waiting for a complete flash (from white to red and back to white) to finish. We will use recursion instead. Once a complete flash is done, we'll call the function again if needed.

You can see a working example in the snippet:

const initArray = [1,1,1,1,1,1];
const colors = ['red', 'green', 'blue'];
let x = 0;
let numberOfFlashes = 0;
function showCircle() {
  setTimeout(()=> {
    color = colors[x];
    console.log(color);
    setTimeout(()=> {
      console.log('white');
      numberOfFlashes++;
      if(numberOfFlashes<initArray.length){
        showCircle();
      }
    }, 400);

    x = (x+1)%3;
  }, 400);
}

showCircle();

Now you can just put your code instead of my console logs and you should get it to work

Upvotes: 1

tghw
tghw

Reputation: 25303

The problem is that you are overwriting x and you're trying to modify a number, j, that's being passed in.

First, the definition of forEach is helpful to read.

Specifically, in the function you're passing in, showCircle, item is the current item of the array, j is the current index of the loop, and x is the original array, in this case it would be initArray. Then, you're overwriting x with let x = 0, and you're trying to increment j, which won't do anything because it's being incremented after it's used.

I think you're looking for something more like this:

// Declare these outside the loop
var x = 0;
var colors = ['blue','pink','green'];

function showCircle(num, j) {
  // Save the current value so it isn't overwritten by the loop/setTimeout combination
  let y = x;
  // Increment x
  x++;
  setTimeout(function () {
    // Get the color, using the modulus operator (%) to start at the beginning again
    var color = colors[y % colors.length];
    // Get the element. num is the current item in the loop from initArray
    var element = document.getElementById(num);
    // Make it glow!
    element.classList.add(`cell-glow-${color}`)
    setTimeout(function () {
      // Make it not glow...
      element.classList.remove(`cell-glow-${color}`)
    }, 400);
    console.log(color);
    // j is the index of num in initArray
  }, speed() * j);
};

function showEachCircle(captureUserClicks) {
  initArray.forEach(showCircle);
}

If you're not familiar with the modulus (or remainder) operator %, it is very useful for looping when you have a limited set of things you want to loop over, in this case colors. In this example, with 3 colors:

0 % colors.length = 0
1 % colors.length = 1
2 % colors.length = 2
3 % colors.length = 0
4 % colors.length = 1
etc..

Upvotes: 2

Related Questions