Search code examples
javascripthtmldomsimple-html-dom

childNode unexpected behaviour


Scenario

I would like to get all child nodes of my div and change it color. Code:

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    myCollection[i].style.color = "red";
  }
}
<div id="divv">

  <h2>JavaScript HTML DOM</h2>

  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>

  <button onclick="myFunction()">Try it</button>
</div>

Error: This is not working. It seems tha in my collection i have all nodes. h2 p text buton. I Expeceted just p h2 and buton.

EDIT Explanation Note: Whitespace inside elements is considered as text, and text is considered as nodes. Comments are also considered as nodes.

So we need to check if node is element node, or use querySelectorAll. Examples in answers below. Thanks for your help.


Solution

  • You could use the children property to access the children of a given node:

    The ParentNode property children is a read-only property that returns a live HTMLCollection which contains all of the child elements of the node upon which it was called.

    - MDN web docs

    function myFunction() {
      var divv = document.getElementById("divv");
      var myCollection = divv.children;
      var len = myCollection.length;
      var i;
      for (i = 0; i < len; i++) {
        myCollection[i].style.color = "red";
      }
    }
    <div id="divv">
      <h2>JavaScript HTML DOM</h2>
      <p>Hello World!</p>
      <p>Hello Norway!</p>
      <p>Click the button to change the color of all p elements.</p>
      <button onclick="myFunction()">Try it</button>
    </div>


    Another way to do with ES6 would be to spread the child nodes into an array and loop through them with a .forEach:

    const myFunction = () => {
      
      [...document.querySelector('#divv').children].forEach(child => {
      
        child.style.color = 'red';
      
      });
      
    }
    <div id="divv">
      <div class="child">
        I am a child
      </div>
      <div>
        <div class="grandchild">
          I am a grand child
        </div>
      </div>
      
      <button onclick="myFunction()">Try it</button>
    </div>

    Alternatively, you could use the .forEach from the NodeList class directly but the previous method gives you more freedom to work with Array's method such as .reduce, .map, etc...

    const myFunction = () => {
      
      document.querySelectorAll('#divv > *').forEach(child => {
      
        child.style.color = 'red';
      
      });
      
    }
    <div id="divv">
      <div class="child">
        I am a child
      </div>
      <div>
        <div class="grandchild">
          I am a grand child
        </div>
      </div>
      
      <button onclick="myFunction()">Try it</button>
    </div>