HTML DOM NodeList Object: Accessing Collections of Nodes

The HTML DOM (Document Object Model) represents the structure of an HTML document as a tree of objects, where each element, attribute, and text within the document is represented as a node. The NodeList object is a crucial part of the DOM, serving as a dynamic collection of nodes. Unlike arrays, a NodeList is a live collection, meaning it automatically updates when changes occur in the DOM. This article will guide you through understanding and using the NodeList object to effectively manage collections of nodes in your web applications.

What is a NodeList?

A NodeList is an object that represents an ordered list of nodes. It is returned by various DOM methods, including:

  • document.querySelectorAll(): Returns a static NodeList of all elements that match a specified CSS selector.
  • element.childNodes: Returns a live NodeList of an element’s child nodes.
  • element.getElementsByTagName(): Returns a live HTMLCollection (which is similar to a NodeList) of elements with a specified tag name.

It’s important to note the difference between a NodeList and an HTMLCollection. While both are collections of nodes, NodeList can contain any node type (elements, text nodes, comments), while HTMLCollection only contains elements. Another key difference is that a NodeList returned by querySelectorAll() is static, meaning changes to the DOM won’t update the collection, while the one returned by childNodes is live.

Purpose of the NodeList Object

The primary purpose of the NodeList object is to:

  • Provide a way to iterate through and access multiple nodes in the DOM.
  • Allow for manipulation of elements based on certain criteria.
  • Facilitate dynamic updates when the underlying DOM changes.

Accessing NodeLists

Let’s explore how to access NodeList objects using different DOM methods:

Using querySelectorAll()

The querySelectorAll() method is a powerful tool for selecting nodes using CSS selectors. It returns a static NodeList containing all matching nodes.

  <ul id="myList1">
    <li class="item">Item 1</li>
    <li class="item">Item 2</li>
    <li>Item 3</li>
    <li class="item">Item 4</li>
  </ul>

<div id="output1"></div>

<script>


    const nodeList_items1 = document.querySelectorAll('#myList1 .item');
    let output1_text = 'Items with class "item": ';
    nodeList_items1.forEach(item => {
        output1_text += item.textContent + ', ';
    });
    document.getElementById('output1').textContent = output1_text.slice(0,-2);


</script>
  • Item 1
  • Item 2
  • Item 3
  • Item 4

In this example, querySelectorAll('#myList1 .item') selects all li elements within the ul with the ID myList1 that have the class item.

Using childNodes

The childNodes property of an element returns a live NodeList containing all child nodes, including element nodes, text nodes, and comment nodes.

<div id="myDiv2">
  <span>Span 1</span>
  <!-- Comment -->
  Text node
  <p>Paragraph</p>
</div>

<div id="output2"></div>

<script>


  const myDiv2_element = document.getElementById('myDiv2');
    const nodeList_childNodes2 = myDiv2_element.childNodes;
    let output2_text = 'Child nodes: ';
    nodeList_childNodes2.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE) {
            output2_text += node.tagName + ', ';
        } else if (node.nodeType === Node.TEXT_NODE) {
            output2_text += 'text, ';
        } else if (node.nodeType === Node.COMMENT_NODE) {
            output2_text += 'comment, ';
        }
    });
     document.getElementById('output2').textContent = output2_text.slice(0, -2);


</script>
Span 1

Text node

Paragraph

This example demonstrates how to retrieve all types of child nodes from a div element and log their types in the output.

NodeList Properties and Methods

The NodeList object provides several properties and methods to access and manipulate the nodes within the collection:

Property/Method Type Description
`length` Property Returns the number of nodes in the list.
`item(index)` or `[index]` Method/Indexer Returns the node at the given index in the list.
`forEach(callback)` Method Executes a provided function once for each node in the NodeList.
`entries()` Method Returns a new Iterator that allows iterating over the list of key/value pairs contained in the NodeList. The keys are numbers, starting from zero.
`keys()` Method Returns a new Iterator that allows iterating over the indexes of the NodeList.
`values()` Method Returns a new Iterator that allows iterating over the values in the NodeList.

Note: NodeList objects are not arrays and do not have array methods like push(), pop(), or slice(). However, the forEach() method, introduced with ES6, is extremely useful for looping through the nodes. πŸ’‘

Working with NodeLists

Here are a few practical examples of how to manipulate NodeList objects:

Iterating Through a NodeList

Using the forEach() method for easy iteration is recommended.

  <ul id="myList3">
    <li class="item">Item A</li>
    <li class="item">Item B</li>
    <li class="item">Item C</li>
  </ul>

  <div id="output3"></div>

<script>


  const nodeList_items3 = document.querySelectorAll('#myList3 .item');
    let output3_text = '';
    nodeList_items3.forEach((item, index) => {
        output3_text += `Item ${index + 1}: ${item.textContent}, `;
        item.style.color = 'blue';
    });
   document.getElementById('output3').textContent = output3_text.slice(0, -2);


</script>
  • Item A
  • Item B
  • Item C

This code iterates through the NodeList, changes the color of each item, and displays their content and index.

Accessing Nodes by Index

You can access individual nodes using the item() method or array-like index notation.

 <ul id="myList4">
    <li>First</li>
    <li>Second</li>
    <li>Third</li>
  </ul>

  <div id="output4"></div>

<script>


  const myList4_element = document.getElementById('myList4');
    const nodeList_items4 = myList4_element.childNodes;
    let output4_text = '';
    if(nodeList_items4 && nodeList_items4.length>1){
        const secondItem = nodeList_items4[1] || nodeList_items4.item(1);
        output4_text = 'Second item: ' + secondItem.textContent;
    }
    document.getElementById('output4').textContent = output4_text;


</script>
  • First
  • Second
  • Third

Here, we access and display the content of the second li element using both the array-like index and the item() method.

Converting a NodeList to an Array

To utilize array methods not directly available in NodeList, convert it to an array using Array.from() or spread syntax:

 <ul id="myList5">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
  </ul>

  <div id="output5"></div>

<script>


    const myList5_element = document.getElementById('myList5');
  const nodeList_items5 = myList5_element.querySelectorAll('li');
  const array_items5 = Array.from(nodeList_items5);
   const array_items5_filtered = array_items5.filter(item => item.textContent.length > 3);
    let output5_text = 'Filtered items: ';
    array_items5_filtered.forEach(item=> output5_text+= item.textContent + ', ')
  document.getElementById('output5').textContent = output5_text.slice(0,-2);


</script>
  • One
  • Two
  • Three
  • Four

This code demonstrates converting the NodeList to an array and applying the filter() array method.

Live vs. Static NodeLists

Understanding the difference between live and static NodeList objects is crucial for avoiding unexpected behavior:

  • Live NodeLists: NodeLists returned by properties like childNodes are live. When you modify the DOM, the NodeList is automatically updated.
  • Static NodeLists: NodeLists returned by methods like querySelectorAll() are static. Changes to the DOM after the collection is retrieved will not update the collection.
 <ul id="myList6">
    <li>Item X</li>
  </ul>

  <div id="output6"></div>

<script>


    const myList6_element = document.getElementById('myList6');
    const liveList_items6 = myList6_element.childNodes;
    const staticList_items6 = myList6_element.querySelectorAll('li');
    myList6_element.appendChild(document.createElement('li')).textContent = 'Item Y';
    let output6_text = '';
    output6_text += 'Live NodeList length: ' + liveList_items6.length + ', ';
    output6_text += 'Static NodeList length: ' + staticList_items6.length;
    document.getElementById('output6').textContent = output6_text;


</script>
  • Item X

In this example, the live NodeList (childNodes) reflects the new list item, while the static NodeList (querySelectorAll()) does not.

Browser Support

The NodeList object is supported by all modern browsers.

Real-World Applications

The NodeList object is used extensively in web development for various purposes:

  • Dynamic Content Updates: Handling user interactions and updating lists of elements.
  • Form Validation: Validating multiple input fields.
  • Interactive Elements: Implementing features that manipulate multiple elements based on user actions.
  • UI Components: Building reusable UI components that interact with multiple DOM nodes.

Conclusion

The HTML DOM NodeList object is a foundational tool for accessing and manipulating collections of nodes in web applications. By understanding how to retrieve and work with NodeList objects, you can build more dynamic, responsive, and feature-rich web experiences. This comprehensive guide has covered the key concepts and practical examples that will enable you to effectively manage collections of nodes in your web development projects.