Search code examples
javascriptdom-manipulation

Why doesn't an event handler inside a for loop work for all iterations?


Working on an Etch-A-Sketch project using Vanilla JS. I ran into a problem with my project where I have a for loop which creates a 16 * 16 grid -

//makes a 16 x 16 grid - default grid
for(let i = 0; i < 16; i++){
    const div =  document.createElement('div');
    div.style.cssText = 'border: 1px solid black; flex: 1';
    container.appendChild(div);
    // div.addEventListener('mouseover', changeBackground);
    for (let j = 0; j < 16; j++){
        div2 = document.createElement('div');
        div2.classList.add('square');
        div.style.display = 'flex';
        div.appendChild(div2);  

        div2.addEventListener('mouseover', changeBackground);
    }
}

Grid created by the for loop

Inside the inner for loop I have set up an event listener which has a callback called changeBackground() - which will randomly change colour when the cursor hovers over the grid - what I was hoping for was to have any square on the grid change colour when the cursor goes over it. However from the image above, only the very last square on the grid changes colour when I hover over the grid freely, whereas any other square on the grid stays white and non-responsive. So my question is: Why is the last grid square in the bottom right the only one to change color whereas every other square remains blank?


function changeBackground(){
    let randomColor = colors[Math.floor(Math.random() * colors.length)];

    if(randomColor === '1'){
        div2.style.backgroundColor = 'red';
        console.log('red');
    } else if(randomColor === '2'){
        div2.style.backgroundColor = 'blue';
        console.log('blue');
    } else if(randomColor === '3'){
        div2.style.backgroundColor = 'yellow';
        console.log('yellow');
    } else if(randomColor === '4'){
        div2.style.backgroundColor = 'orange';
        console.log('orange');
    } else{
        div2.style.backgroundColor = 'green';
        console.log('green');
    }
}

Solution

  • All you need to do is get that element reference in your changeBackground function

    function changeBackground(e){
        var div = e.target; // the current div you want to change
    
        // do your stuff
    
        div.style.backgroundColor = 'red';
    }
    

    I put together a quick example do demonstrate the element references. It gets passed to your mouseover function automatically (I used button but it works for any element) and I called it e. Then you need to pull out the current element using e.target.

    var btns = document.getElementsByTagName('button');
    
    for (var i = 0; i < btns.length; i++) {
      btns[i].addEventListener('mouseover', whichButton);
    }
    
    function whichButton(e) {
      var btn = e.target; // <- This is your current element (in your case, div2)
      console.log(btn);
      
      var span = document.getElementById('spanMO');
      span.textContent = btn.textContent;
    }
    <button>First</button><br/>
    <button>Second</button><br/>
    <button>Third</button><br/>
    
    <p>
    Mouseover: <span id="spanMO"></span>
    </p>