skip to Main Content

I am stuck on simple issue – how can I target source of event listener (div) which is dynamically created in plain JS and change its style?

My goal is to have dynamically created grid from divs (which is working great), and when user hovers over the divs, they change their background color.

I have come up with an idea, but it’s not working. I am not sure if this approach is even correct, as isn’t the source of mouseover user event user? Not a div itself?

Please, do you have idea how to solve this issue?

function createGrid() {
  for (let i = 0; i < 256; i++) {
    const node = document.createElement("div");
    node.classList.add('grid-item')
    document.getElementById("gridc").appendChild(node);
  }
}

window.addEventListener("load", createGrid());

let items = document.querySelectorAll('.grid-item');
for (var i = items.length; i--;) {
  items[i].addEventListener("mouseover", function(e) {
    e.source.style.backgroundColor = 'blue';
  });
}
.grid-container {
  display: grid;
  width: 60px;
  grid-template-columns: 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100%;
}

.grid-item {
  border: 1px solid rgba(0, 0, 0, 0.8);
  padding: 20px;
}

.grid-item:hover {
  background-color: blue;
}
<div class="grid-container" id="gridc"></div>

3

Answers


  1. The main issue in your code is because Event objects have no source property. You should use target instead to reference the element which raised the event.

    There’s also some other issues which need to be addressed.

    • You need to provide the createGrid() function reference to the load handler, not the return value of invoking that function immediately.
    • Use the mouseenter event, not mousemove. The latter will fire for every pixel that the mouse moves over the element, which is far more than required in this case.
    • Bind the mouse event handler at the point you create each cell. There’s no need for two separate loops.
    • Retrieve the #gridc element from the DOM once when the page loads, not in each iteration of the loop. DOM operations are very slow (relatively speaking) and should be done sparingly. In fact it may even be more performant to build the entire grid from a single HTML string and append it to the DOM in a single operation. I’ll leave this as an exercise for the OP to determine, though.
    const gridContainer = document.querySelector('#gridc');
    const cellMouseEnterHandler = e => e.target.style.backgroundColor = '#00F';
    
    function createGrid() {
      for (let i = 0; i < 256; i++) {
        const node = document.createElement("div");
        node.classList.add('grid-item')
        node.addEventListener('mouseenter', cellMouseEnterHandler);
        gridContainer.appendChild(node);
      }
    }
    
    window.addEventListener("load", createGrid);
    .grid-container {
      display: grid;
      width: 60px;
      grid-template-columns: 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100%;
    }
    
    .grid-item {
      border: 1px solid rgba(0, 0, 0, 0.8);
      padding: 20px;
    }
    
    .grid-item:hover {
      background-color: blue;
    }
    <div class="grid-container" id="gridc"></div>
    Login or Signup to reply.
  2. you can also use event delegation with mousemove event :

    const gridContainer = document.querySelector('#gridc');
      
    for (let i = 0; i < 256; i++)
      gridContainer
       .appendChild( document.createElement('div'))
       .classList.add('grid-item');
    
    gridContainer.addEventListener('mousemove', e =>
      {
      if (!e.target.matches('.grid-item')) return
      e.target.style.backgroundColor = 'red';
      })
    .grid-container {
      display: grid;
      width: 60px;
      grid-template-columns: 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100% 100%;
    }
    
    .grid-item {
      border: 1px solid rgba(0, 0, 0, 0.8);
      padding: 20px;
    }
    <div class="grid-container" id="gridc"></div>
    Login or Signup to reply.
  3. Your approach is almost there! However, the issue lies in how you’re trying to access the element that triggered the event. In JavaScript, within an event listener, you can access the element that triggered the event via event.target.

    Here’s a revised version of your code:

    function createGrid() {
      const gridContainer = document.getElementById("gridc");
      for (let i = 0; i < 256; i++) {
        const node = document.createElement("div");
        node.classList.add('grid-item');
        node.addEventListener("mouseover", function(e) {
          e.target.style.backgroundColor = 'blue';
        });
        gridContainer.appendChild(node);
      }
    }
    
    window.addEventListener("load", createGrid);
    

    Changes made:

    Inside createGrid() function, each dynamically created div now has an event listener attached directly to it.
    Within the event listener function, e.target refers to the specific div that triggered the mouseover event, allowing you to change its background color.
    This revised code should now change the background color of each individual div when hovered over.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search