How can I add color on clicking specific elements that were generated by JS

Viewed 74

I'm creating a pixel art maker with HTML, CSS, and vanilla JS. I've created my UI for the most part, but I can't get the functionality working. I've tried:

let cell = document.body.querySelectorAll('.grid-square');
cell.addEventListener('click', function() {
    cell.style.backgroundColor = 'red';
});

But my page 'addEventListener' isn't a function. How do I get my JS to load after the HTML so I can get this to work?

https://jsfiddle.net/wygtshu6/1/

2 Answers
let cells = document.body.querySelectorAll('.grid-square'); // querySelectorAll return all elements which have grid-square class.

for(let i = 0; i < cells.length; i++){
        cells[i].addEventListener('click', function(){
            cells[i].style.backgroundColor = "red";
    });
}

There are just 2 steps you need to get this working:

  1. querySelectorAll returns an array of elements so you need to loop through them to add the listener to each cell:
function setUpCellListeners(){
    let cells = document.querySelectorAll('.grid-square');
    cells.forEach((cell) => {
        cell.addEventListener('click', function() {
            cell.style.backgroundColor = 'red';
        });
   });
}
  1. You need to do this after the cells have been created. They are created in the createGrid function, so we can do that by calling it at the end of that function:
//function to build the grid based on user input
function createGrid(height = 25, width = 25) {

    /* code to set up grid.... */

    // NOW we can set up our listeners because our grid is created
    setUpCellListeners();
}

Working Example:

let canvas = document.querySelector('.canvas');
let button = document.querySelector('button');
let high;
let wide;
let color = document.querySelector('.colorChoice').value;


function setUpCellListeners(){
    let cells = document.querySelectorAll('.grid-square');
    cells.forEach((cell) => {
       cell.addEventListener('click', function() {
           cell.style.backgroundColor = 'red';
       });
    });
}


//function to build the grid based on user input
function createGrid(height = 25, width = 25) {
    canvas.innerHTML = '';
    for (let i = 0; i < height; i++) {
        let row = document.createElement('div');
        row.classList.add('row');
        canvas.appendChild(row);
        for (let j = 0; j < width; j++) {
            let cell = document.createElement('div');
            cell.classList.add('grid-square');
            row.appendChild(cell);
        }
    }
    setUpCellListeners();
}

//listens for input of rows and columns
button.addEventListener('click', function() {
    high = parseInt(document.querySelector('.column-input').value);
    wide = parseInt(document.querySelector('.row-input').value);
    if (Number.isNaN(high) || Number.isNaN(wide)) {
        createGrid();
    } else {
        createGrid(wide, high);
    }
});
//Default grid built on load
window.onload = createGrid(25, 25);
.grid-square {
    height: 12px;
    width: 12px;
    border: 1px black solid;
}

.row {
    display: flex;
    justify-content: center;
}

.canvas {
    max-height: inherit;
    max-width: 75%;
}
   <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    
    <!-- Navbar -->
    <nav class="navbar navbar-dark bg-dark">
        <span class="navbar-brand mb-0 h1 mx-auto navbar-brand">Pixel Art Maker</span>
    </nav>

    <!-- Container to put grid in -->
    <div class="container shadow p-3 mb-5 bg-white rounded mt-5 main">
      
      <div class="container canvas d-flex-inline">
        
      </div>

      <form class="d-flex-inline w-50 mx-auto">
        <div class="d-flex">
          <div class="form-group w-25 ml-auto mr-2">
            <label class="d-block text-center" for="gridRows">Rows</label>
            <input type="number" class="form-control row-input" id="gridRows">
          </div>
          <div class="form-group w-25 mr-auto ml-2">
            <label class="d-block text-center" for="gridColumns">Columns</label>
            <input type="number" class="form-control column-input" id="gridColumns">
          </div>
        </div>  
        </form>
        <div class="form-group w-25 mx-auto">
          <button type="submit" class="btn btn-primary w-100">Submit</button>
        </div>
      <form class="d-flex-inline w-50 mx-auto">
        <div class="form-group w-25 mx-auto">
          <label for="color">Color</label>
          <input type="color" class="form-control colorChoice" id="color">
        </div>
      </form>
    </div>

<!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS, then local JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>

Working code in a jsfiddle: https://jsfiddle.net/has024gr/

Related