skip to Main Content

I am completing the "etch-a-sketch" challenge as part of TOP curriculum. I have successfully created a 16 x 16 grid utilizing JS DOM manipulation and CSS grid. The second part of my problem is to make each individual grid-item/cell change background color on hover. I chose to use JS with the mouseover Eventlistener, but also saw the CSS: hover Selector as a viable option when googling for information.

I have created 2 functions overing and outing to change the background color of the grid-item on hover using the "mouseover" event listener. The functions only work on the first generated cell/grid-item. May someone please explain how I can get my overing and outing functions to work on all grid-items.only 1st grid-item working

//Function and call to generate 16x16 grid of divs. 
document.getElementById("container");

function makeGrid(rows, cols) {
  container.style.setProperty('--grid-rows', rows)
  container.style.setProperty('--grid-cols', cols)
  for (c = 0; c < (rows * cols); c++) {
    let cell = document.createElement("div");
    cell.innerText = (c + 1);
    container.appendChild(cell).className = "grid-item";
  };
};
makeGrid(16, 16);
//Function to change background color of individual "grid-item" on hover.
document.querySelector('.grid-item').addEventListener('mouseover', overing);
document.querySelector('.grid-item').addEventListener('mouseout', outing);

function overing(ev) {
  ev.currentTarget.style.backgroundColor = 'red';
  console.log('mouseenter div');
}

function outing(ev) {
  ev.currentTarget.style.backgroundColor = 'white';
  console.log('mouseleave div');
}
:root {
  --grid-cols: 1;
  --grid-rows: 1;
}

#container {
  display: grid;
  grid-gap: 1em;
  grid-template-columns: repeat(var(--grid-cols), 1fr);
  grid-template-rows: repeat(var(--grid-rows), 1fr);
}

.grid-item {
  padding: 1em;
  border: 1px solid black;
  text-align: center;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sketch-Book</title>
  <link rel="stylesheet" type="text/css" href="etchStyles.css" />
</head>

<body>
  <div id="container">
  </div>
</body>
<script type="text/javascript" src="etchScript.js"></script>

</html>

3

Answers


  1. @Titus is right. But since you are using javascript to create each DOM node, you can exploit this fact to attach event listeners at creation time. Ex:

    const overing = (ev) => {
      ev.currentTarget.style.backgroundColor = 'red';
      //console.log('mouseenter div');
    };
    
    const outing = (ev) => {
      ev.currentTarget.style.backgroundColor = 'white';
      //console.log('mouseleave div');
    }
    
    const makeGrid = (rows, cols) => {
      container.style.setProperty('--grid-rows', rows)
      container.style.setProperty('--grid-cols', cols)
      for (c = 0; c < (rows * cols); c++) {
        let cell = document.createElement("div");
        cell.innerText = (c + 1);
        cell.classList.add('grid-item');
        
        //  attach listeners here since you have a reference to the DOM node
        cell.addEventListener("mouseover", overing);
        cell.addEventListener("mouseout", outing);
        
        container.appendChild(cell);
      };
    };
    
    makeGrid(16, 16);
    section {
      --grid-cols: 1;
      --grid-rows: 1;
    }
    
    #container {
      display: grid;
      grid-gap: 1em;
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      grid-template-rows: repeat(var(--grid-rows), 1fr);
      
    }
    
    .grid-item {
      padding: 1em;
      border: 1px solid black;
      text-align: center;
    }
    
    .grid-item:hover {
      cursor: pointer;
    }
    <section>
        <div id="container">
        </div>
    </section>
    Login or Signup to reply.
  2. You could use css :hover, here is an example with a 3×3 grid:

    .grid {
      display: grid;
      grid-template: repeat(3, 30vh) / repeat(3, 30vw);
      background-color: white;
      height: 94vh;
      width: 94vw;
      grid-row-gap:1vh;
      grid-column-gap:1vw;
    }
    
    .grid_element {
      display: flex;
      height: 100%;
      width: 100%;
      background-color: gray;
    }
    
    .grid_element:hover {
      background-color: red;
    }
    <div class="grid">
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
      <div class="grid_element"></div>
    </div>
    Login or Signup to reply.
  3. All modern browsers support template ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template so lets’ use that instead of manually creating an element so out code can be smaller – especially if you add more content to each "cell" such as a set of spans, divs etc.

    You can determine what you want for event handlers but you can add those right in the same loop when creating them.

    NOTE: Probably want to create a new DIV just to append all the NEW items to before hitting the DOM and appending them all at once but I will leave that exercise to you as outside the question scope.

    function makeGrid(rows, cols) {
      const container = document.getElementById("container");
      const template = document.getElementById("grid-cell-template");
      for (let c = 0; c < (rows * cols); c++) {
        const cloneCell = template.content.cloneNode(true);
        const newItem = cloneCell.querySelector(".grid-item");
        newItem.textContent = (c + 1);
        newItem.addEventListener('mouseenter', mouseEnterEventHandler);
        newItem.addEventListener('mouseleave', mouseLeaveEventHandler);
        newItem.addEventListener('mouseover', mouseOverEventHandler);
        container.appendChild(newItem);
      }
    }
    makeGrid(16, 16);
    
    function mouseEnterEventHandler(event) {
      event.currentTarget.style.backgroundColor = '#FF000022';
    }
    
    function mouseLeaveEventHandler(event) {
      event.currentTarget.style.backgroundColor = '#FFFFFF';
      event.target.style.borderColor = "#000000";
    }
    
    function mouseOverEventHandler(event) {
      event.target.style.borderColor = "#00FF00";
    }
    body {
      font-size: 16px;
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    :root {
      --grid-cols: 16;
      --grid-rows: 16;
    }
    
    #container {
      display: grid;
      grid-gap: 0.5em;
      grid-template-columns: repeat(var(--grid-cols), 1fr);
      grid-template-rows: repeat(var(--grid-rows), 1fr);
    }
    
    .grid-item {
      padding: 1em;
      border: 1px solid #000000;
      text-align: center;
    }
    <body>
      <div id="container">
      </div>
      <template id="grid-cell-template">
      <div class="grid-item"></div>
      </template>
    </body>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search