zolty13
zolty13

Reputation: 2231

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.

Upvotes: 0

Views: 381

Answers (2)

Ivan
Ivan

Reputation: 40648

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>

Upvotes: 3

CertainPerformance
CertainPerformance

Reputation: 370729

Text nodes do not have style attributes. If you want to use childNodes, check that the nodeType is 1 (an Element node) first:

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    if (myCollection[i].nodeType === 1) 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>

But I would prefer using querySelectorAll and forEach here:

function myFunction() {
  document.querySelectorAll('#divv > *')
    .forEach(child => child.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>

(or, you could simply set #divv's style.color to red)

Upvotes: 4

Related Questions