Search code examples
javascriptperformancefirefoxgriduser-input

Page slows browser down when input is high


I am building an etch-a-sketch browser version for the odin project. There is a prompt message that asks input from the user and creates a grid based on the input.

If the input is 15 that should give a 15x15 grid.

Unfortunately the higher the input the more time it takes for the page to load. Any ideas why?

const container = document.querySelector('#container');
const btn = document.querySelector('#btn');
/*
btn.addEventListener('click', () => {
  squares.forEach(square => {
    square.style.backgroundColor = 'white';
  });
});
*/
btn.addEventListener('click', () => addGrid());

function addGrid() {

  let content = document.createElement('div');
  let input = prompt("Please enter the number of squares per side (2 - 100)");

  while ((input == null || input > 100 || input < 2 || isNaN(input))) {
    input = prompt("Please enter the number of squares per side (2 - 100)");
  }

  for (let i = 0; i <= input * input; i++) {

    container.style.cssText = 'grid-template-rows: repeat(' + input + ' , 1fr); grid-template-columns: repeat(' + input + ', 1fr)';
    content = document.createElement('div');
    content.classList.add('square');
    container.appendChild(content);
    squares = container.querySelectorAll('.square')

    squares.forEach(square => {
      square.addEventListener('mouseenter', () => {
        square.style.backgroundColor = 'black';
      });
    });

    squares.forEach(square => {
      square.addEventListener('mouseleave', () => {
        square.style.backgroundColor = 'black';
      });
    });

  }
  return content;
}
<button id="btn">Click</button>
<div id="container"></div>


Solution

  • You need to move the event handlers outside the loop. Also you need to use < instead of <= in the loop

    Even better, delegate from container

    Here is a working version - you could use calc() in the css to size the individual squares

    Using delegated event handling

    const container = document.getElementById('container');
    const btn = document.getElementById('btn');
    const reset = document.getElementById('reset');
    
    const mclick = e => { 
      const tgt = e.target;
      if (tgt.matches(".square")) tgt.classList.toggle("clicked");
    }
    const mhover = e => {
      const tgt = e.target;  
      if (!tgt.matches(".square")) return; // not a square
      tgt.classList.toggle("active",e.type==="mouseover")
    }
    
    const resetGrid = () => container.querySelectorAll(".square")
      .forEach(sq => { 
        ["clicked","active"]
        .forEach(cls => sq.classList.remove(cls))
        });
    
    const addGrid = () => {
    
      let content = document.createElement('div');
      let input = prompt("Please enter the number of squares per side (2 - 100)");
    
      while ((input == null || input > 100 || input < 2 || isNaN(input))) {
        input = prompt("Please enter the number of squares per side (2 - 100)");
      }
    
      for (let i = 0; i < input * input; i++) {
    
        container.style.cssText = 'grid-template-rows: repeat(' + input + ' , 1fr); grid-template-columns: repeat(' + input + ', 1fr)';
        let content = document.createElement('div');
        content.classList.add('square');
        content.textContent = i
        container.appendChild(content);
      }
    };
    btn.addEventListener('click',addGrid);
    
    container.addEventListener("mouseover",mhover);
    container.addEventListener("mouseout",mhover);
    container.addEventListener("click",mclick);
    reset.addEventListener("click",resetGrid);
    #container { display:grid; }
    div.square { height: 50px; width: 50px; border:1px solid black;}
    div.square.active { background-color: black;}
    div.square.clicked { background-color: red;}
    <button id="btn">Start</button><button id="reset">Reset</button>
    <div id="container"></div>