DOM Nodes
You’ve already learned about the W3C DOM and, in the code examples of previous section, you used various DOM objects, properties, and methods.
In this section you begin exploring how JavaScript can directly interact with the DOM. In particular, you learn some new ways to navigate around the DOM, selecting particular DOM objects that represent parts of the page’s HTML contents. You see how to create new elements, how to add, edit, and remove nodes of the DOM tree, and how to manipulate elements’ attributes.
In section “First Steps with JavaScript,” you were introduced to the W3C Document Object Model (DOM) as a hierarchical tree of parent-child relationships that together form a model of the current web page. By using appropriate methods, you can navigate to any part of the DOM and retrieve details about it.
You probably recall that the top-level object in the DOM hierarchy is the window object, and that one of its children is the document object. In this section we mainly deal with the document object and its properties and methods.
Take a look at the simple web page
<!DOCTYPE html> <html> <head> <title>To-Do List</title> </head> <body> <h1>Things To Do</h1> <ol id="toDoList"> <li>Mow the lawn</li> <li>Clean the windows</li> <li>Answer your email</li> </ol> <p id="toDoNotes">Make sure all these are completed by 8pm so you can watch the game on TV!</p> </body> </html>
shows the page displayed in Mozilla Firefox
When page loading has completed, the browser has a full, hierarchical DOM representation of this page available for us to examine. below snapshot shows a simplified version of how part of that representation might look.
Look at how the tree diagram of snapshot1 relates to the code in snapshot2
The <html> element contains all the other markup of the page. It is the parent element to two immediate child elements, the <head> and <body> elements. These two elements are siblings, as they share a parent. They are also parents themselves; the <head> element has one child element, <title>, and the <body> element three children: the <h1> heading, the ordered list <ol>, and a paragraph, <p>. Of these three siblings, only <ol> has children, those being three <li> line item elements. Various of these elements of the tree contain text, shown represented in the gray boxes in snapshot2.
The DOM is constructed as a hierarchy of such relationships. The boxes that make up the junctions and terminating points of the tree diagram are known as nodes.
Types of Nodes
snapshot1 shows various element nodes, each of which represents an HTML element such as a paragraph element, <p>, along with some text nodes, representing the text content of such page elements.
There are a number of other node types, representing such information as each element’s attributes, HTML comments, and other information relevant to the page. Many node types can, of course, contain other nodes as children.
Each different type of node has an associated number known as its nodeType property.
The childNodes Property
A useful DOM property for each node is a collection of its immediate children. This array-like list is called childNodes, and it enables you to access information about the children of any DOM node.
The childNodes collection is a so-called NodeList, in which the items are numerically indexed. A collection looks and (for the most part) behaves like an array— you can refer to its members like those of an array, and you can iterate through them like you would for an array. However, there are a few array methods you can’t use, such aspush() and pop(). For all the examples here, you can treat the collection like you would a regular array.
A node list is a live collection, which means that any changes to the collection to which it refers are immediately reflected in the list; you don’t have to fetch it again when changes occur.
Try it Yourself: Using the childNodes Property
You can use the collection returned by the childNodes property to examine the ordered list element <ol > that appears given above list. You’re going to write a small function to read the child nodes of the <ol > element and return the total number present in the list
First, you can retrieve the <ol > element via its ID.
var olElement = document.getElementById("toDoList");
The child nodes of the <ol > element will now be contained in the object
olElement.childNodes
You only want to select the <li> elements in the list, so you now want to step through the childNodes collection, counting just those nodes for which nodeType==1 (i.e., those corresponding to HTML elements), ignoring anything else contained in the ordered list element such as comments and whitespace. Remember, you can treat the collection pretty much like an array; here you use the length property as you would for an array:
var count = 0; for (var i=0; i < olElement.childNodes.length; i++) { if(olElement.childNodes[i].nodeType == 1) count++; }
Let’s cook up a little function to carry out this task when the page has loaded, and output the result with an alert dialog:
Create a new HTML page in your editor and enter the code
<!DOCTYPE html> <html> <head> <title>To-Do List</title> </head> <body> <h1>Things To Do</h1> <ol id="toDoList"> <li>Mow the lawn</li> <li>Clean the windows</li> <li>Answer your email</li> </ol> <p id="toDoNotes">Make sure all these are completed by 8pm so you can watch the game on TV!</p> </body> </html>
Incorporate the preceding JavaScript code into a <script> element in the page head, and load the page into the browser.
shows the result of loading the page in Mozilla Firefox.
firstChild and lastChild
There is a handy shorthand for selecting the first and last elements in the childNodes array.
firstChild is, unsurprisingly, the first element in the childNodes array. Using firstChild is equivalent to using childNodes[0].
To access the last element in the collection, you gain a big advantage by using lastChild. To access this element you would otherwise have to do something like this:
var lastChildNode = myElement.childNodes[myElement.childNodes.length - 1];
That’s pretty ugly. Instead, you can simply use
var lastChildNode = myElement.lastChild;
The parentNode Property
The parentNode property, unsurprisingly, returns the parent node of the node to which it’s applied. In the previous example, you used
var lastChildNode = myElement.lastChild;
Using parentNode you can go one step back up the tree. The line
var parentElement = lastChildNode.parentNode;
would return the parent element of lastChildNode, which is, of course, the object myElement.
nextSibling and previousSibling
Sibling nodes are nodes that share a parent node. When applied to a specified parent node, these read-only properties return the next and previous sibling nodes, respectively, or null if there is no such node.
var olElement = document.getElementById("toDoList"); var firstOne = olElement.firstChild; var nextOne = firstOne.nextSibling;.
Remember that, depending on which browser you use, whitespace in your HTML code may create text nodes in the DOM. The node you’re working with may have more siblings than you thought!
Node Value
In addition to nodeType, the DOM offers the property nodeValue to return the value stored in a node. You generally want to use this to return the text stored in a text node.
Let’s suppose that instead of counting the list items in the previous example, you wanted to extract the text contained in the <p> element of the page. To do this you need to access the relevant <p> node, find the text node that it contains, and then use nodeValue to return the information:
var pElement = document.getElementById("toDoNotes"); for (var i=0; i < pElement.childNodes.length; i++) { if(pElement.childNodes[i].nodeType == 3) { text += pElement.childNodes[i].nodeValue; }; } alert("The paragraph says:\n\n" + text );
Node Name
The nodeName property returns the name of the specified node as a string value. The values returned by the nodeName value are summarized give below. The nodeName property is read-only—you can’t change its value.
Where nodeName returns an element name, it does so without the surrounding < and > that you would use in HTML source code:
var pElement = document.getElementById("toDoNotes"); alert( pElement.nodeName); // alerts 'P'