skip to Main Content

i’m currently working on an etch-a-sketch on the odin project. Here’s the code I’ve come up with.

const container = document.querySelector(".container");
const input = document.querySelector("input");
const submitBtn = document.querySelector("button");

function createGrid() {
    let value=input.value;
    for (let i = 0; i < value; i++) {

        
        const createDivRow = document.createElement("div");
        createDivRow.classList.add("gridrow")
         createDivRow.textContent = i;
        container.appendChild(createDivRow);
    }
    
}

function createGridItems() {
    let value = input.value;
    for (let i = 0; i < value; i++) {
        const divRow = document.querySelectorAll(".gridrow");
        const createDivItem = document.createElement("div");
        createDivItem.textContent = "aa";
        divRow.appendChild(createDivItem);
    }
}

submitBtn.addEventListener("click", createGrid);
submitBtn.addEventListener("click", createGridItems);

In the createGrid() function, I aim to create n number of divs(n being the user input from an input textbox), which I have succeeded. The result was n number of divs with class="gridrow" in the con†ainer.

In the createGridItems() function, I’d like to put the same number of divs "n" into each .gridrow row(which I’ve given the variable divRow).

I tried declaring const divRow = document.querySelector(".gridRow") and the result was n number of divs in the FIRST .gridrow div, which is almost what I wanted.

So, I figured I’d declare const divRow = document.querySelectorAll(".gridrow") to target all the .gridrow I’ve created and put n number of divs into EACH .gridrow div. As a result, all I got was just empty n number of .gridrow divs, without the divs that I want.

Can anyone tell me where I’ve gone wrong ? I was sure the code above would work because I’ve already targeted all the .divrow divs when I declare divRow = document.querySelectorAll(".gridrow").

Thank you!

2

Answers


  1. That’s because querySelectorAll() returns a static (not live) NodeList:

    As per MDN:

    The Document method querySelectorAll() returns a static (not live)
    NodeList representing a list of the document’s elements that match the
    specified group of selectors.

    While NodeList is not equal to array, it’s called array-alike but when it’s static, any changes in the DOM will not affect the content of the nodes collection.

    As per MDN:

    Static NodeLists

    In other cases, the NodeList is static, where any changes in the DOM do not affect the content of the collection.
    The ubiquitous document.querySelectorAll() method returns a static
    NodeList.

    That said, you have to convert the NodeList to an array first, then do your changes, and finally, inject your html and the simplest way to convert it to an array is by using the spread operator, like so:

    function createGridItems() {
      let value = input.value;
      for (let i = 0; i < value; i++) {
        // wrap with brackets, then use spread
        const divRow = [...document.querySelectorAll(".gridrow")];
        const createDivItem = document.createElement("div");
        createDivItem.textContent = "aa";
        // use push instead of appendChild
        divRow.push(createDivItem);
        // now loop throgh divrow
        let html="";
        divRow.forEach(el=> html+=el.outerHTML);
        document.querySelector("WHATEVER_SELECTOR_YOU_WANT").innerHTML = html
      }
    }
    
    Login or Signup to reply.
  2. document.querySelectorAll returns a NodeList (a collection of elements).

    If you checked the javascript console, your code throws an error when trying to .appendChild over the collection.

    You instead needed to iterate over that collection and for each item (being a .gridrow) append there a number of elements.

    This is a quick demo:

    const container = document.querySelector(".container");
    const input = document.querySelector("input");
    const submitBtn = document.querySelector("button");
    
    function createGrid() {
        const value = input.value;
        for (let i = 0; i < value; i++) {        
            const createDivRow = document.createElement("div");
            createDivRow.classList.add("gridrow")
             createDivRow.textContent = i;
            container.appendChild(createDivRow);
        }
        
    }
    
    function createGridItems() {  
        const value = input.value;
        //here you select the rows as .gridrow elements
        const divRows = document.querySelectorAll(".gridrow");    
        //iterate over each one of them
        divRows.forEach(divRow =>{
            //and append to it a new div for as many times as the value fetched from the input element
            for(let i=0;i < value; i++){
              const createDivItem = document.createElement("div");
              createDivItem.textContent = "aa";
              divRow.appendChild(createDivItem);
            }        
        });       
    }
    
    submitBtn.addEventListener("click", createGrid);
    submitBtn.addEventListener("click", createGridItems);
    .gridrow{
      border: solid 1px;  
      margin-top: 1em;
    }
    
    .gridrow > div {
      border: solid 1px red;
      margin-left: 1em;
      display: inline-block;
    }
    <div class="container"></div>
    
    <input type="text">
    <button>submit</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search