Switching the color of a randomized element

Hi I’m in need of a little help.

What I’m trying to create: When the window loads I want a single random square to turn gold after its been clicked. (I do not want to know what square this is)

I thought I was on the right track, but I’m getting a reference error telling me ‘specialSquare’ is not defined.

Can someone please tell me where I went wrong in this code.
Codepen : https://codepen.io/jtog95/pen/MWyWBaG

var square1 = document.getElementById('s1');
var square2 = document.getElementById('s2');
var square3 = document.getElementById('s3');

window.onload = function() {
    createSpecialSquare();
}

squares = [square1, square2, square3];

function createSpecialSquare(){
    for(var i = 0; i < squares.length; i++){
        var specialSquare = Math.floor(Math.random() * squares[i].length + 1);
        specialSquare.onclick = function() {
            if(specialSquare) {
                specialSquare.style.backgroundColor = 'gold';
            }
        }

    }
}


console.log(specialSquare)

This has something to do with variable scope. Basically, the var keyword is only working while inside the function scope.

For Example:

function App() {
  var name = "Nano";
  console.log(name); // will work
}

console.log(name); // will not work
  1. This Math.floor(Math.random() * squares[i].length + 1) is giving you NaN, you can’t attach an onclick to NaN.

  2. squares[someIndex] does not have a length property on it. You will get undefined (which is where NaN is comming from)

  3. Even if you did get a number you still can’t attach an onclick to a number, it has to be an HTML element.

Ah ok thank you lasjorg. There was a lot of mistakes in the last iteration. I’ve updated my code, I feel like I’m very close, but I still get can’t it working.

var square1 = document.getElementById('s1');
var square2 = document.getElementById('s2');
var square3 = document.getElementById('s3');

window.onload = function() {
    createSpecialSquare();
}

var squares = [square1, square2, square3];

function createSpecialSquare(){
    for(var i = 0; i < squares.length; i++){
        var specialSquare = Math.floor(Math.random() * squares.length + 1);
        squares.onclick = function() {  
            if(squares[specialSquare]) {
                squares[specialSquare].style.backgroundColor = 'gold';
            }
        }
    }
}

squares is an array, you can’t attach an onclick to an array.

1 Like

void post sorry--------

I’m honestly stumped. I can’t think of how I would do it without an array. I know the code works because I hard coded :

square1.onclick = function()

it randomized the square that changed color every time I reloaded the page and clicked on square1.

You have to use the random number you are generating as the index for the array to select the element for the event listener.


I’m assuming you want to attach the event listener to one of the three elements randomly and that element is the one that should change color when clicked?

You may want to check your assumptions about:

  1. What number range you are generating and if that fits with the array (MDN: Math.random, Google).

  2. If the location where you are generating the number makes sense. If you have it inside the for loop, the first number generated will be for the element event listener, and the last number will be for the element you set the style on. E.g. 1, 1, 0 === the second square gets the event listener but clicking it will make the first square yellow.

  3. If you need a loop at all?

I’d suggest using querySelectorAll and use the square class for the selector. That will give you a NodeList, which is an array-like structure. Then generate the random number and attach the event listener to it using bracket notation. Inside the event listener callback function, you can get the event target of the click and set its style.

document.addEventListener("DOMContentLoaded", () => {
  const squares = document.querySelectorAll(".square");
  const randomIndex = Math.floor(Math.random() * squares.length);

  squares[randomIndex].addEventListener("click", ({ target }) => {
    target.style.backgroundColor = "gold";
  });
});

Side note: You may want to remove the event listener after you have used it if you only want it to be used one time per page load.

1 Like

Thanks lasjorg! I really appreciate that you made me think about the solution before giving it to me. I still had to reveal the answer, because there was some syntax that I didn’t have experience with. I now pretty much understand everything that’s going on in your solution.
I just have one question. Can you explain this to me.

({target})

Why is it wrapped in both parenthesis and brackets? What exactly is that communicating to the target?

It is object destructuring used for the parameter. It gets the target property from the event object.

// These are the same
const target = event.target;
const { target } = event;

Here is a simple example:

const user = {
  name: 'John',
};

function logName({ name }) {
  console.log(name); // John
}

logName(user);