Chapter 10
In This Chapter
Getting to know the DOM (Document Object Model)
Working with nodes
Moving around the tree
Selecting elements
“No object is mysterious. The mystery is your eye.”
— Elisabeth Bowen
Understanding the DOM is key to being able to manipulate the text or HTML in a web page. Using the DOM, you can create animations, update data without refreshing web pages, move objects around in a browser, and much more!
The Document Object Model is the interface for JavaScript to talk to and work with HTML documents inside of browser windows. The DOM can be visualized as an inverted tree, with each part of the HTML document branching off of its containing part.
Listing 10-1 is the markup for a web page. The DOM representation is shown in Figure 10-1.
Listing 10-1: An HTML Document
<html>
<head>
<title>Bob's Appliances</title>
</head>
<body>
<header>
<img src="logo.gif" width="100" height="100" alt="Site Logo">
</header>
<div>
<h1>Welcome to Bob's</h1>
<p>The home of quality appliances</p>
</div>
<footer>
copyright © Bob
</footer>
</body>
</html>
A DOM tree is made up of individual components, called nodes. The main node, from which every other node springs, is called the document node. The node under the document node is the root element node. For HTML documents, the root node is HTML. After the root node, every element, attribute, and piece of content in the document is represented by a node in the tree that comes from another node in the tree.
The DOM has several different types of nodes:
HTML DOM trees resemble family trees in the hierarchical relationship between nodes. In fact, the technical terms used to describe relationships between nodes in a tree take their names from familial relationships.
Because HTML documents often have multiple elements that are of the same type, the DOM allows you to access distinct elements in a node list using an index number. For example, you can refer to the first <p>
element in a document as p[0]
, and the second <p>
element node as p[1]
.
In Listing 10-2, the three <p>
elements are all children of the <div>
element. Because they have the same parent, they are siblings.
Listing 10-2: Demonstration of Parent, Child, and Sibling Relationships in an HTML Document
<html>
<head>
<title>The HTML Family</title>
</head>
<body>
<section> <!-- proud parent of 3 p elements, child of body -->
<p>First</p> <!-- 1st child of section element, sibling of 2 p elements -->
<p>Second</p> <!-- 2nd p child of section element, sibling of 2 p elements -->
<p>Third</p> <!-- 3rd p child of section element, sibling of 2 p elements -->
</section>
</body>
</html>
By understanding the relationships between document nodes, you can use the DOM tree to find any element within a document.
Listing 10-3 is an HTML document containing a script that outputs all the child nodes of the section
element.
Listing 10-3: Displaying the Child Nodes of the section Element
<html>
<head>
<title>The HTML Family</title>
</head>
<body>
<section> <!-- proud parent of 3 p elements, child of body -->
<p>First</p> <!-- 1st child of section element, sibling of 2 p elements -->
<p>Second</p> <!-- 2nd p child of section element, sibling of 2 p elements -->
<p>Third</p> <!-- 3rd p child of section element, sibling of 2 p elements -->
</section>
<h1>Nodes in the section element</h1>
<script>
var myNodelist = document.body.childNodes[1].childNodes;
for (i = 0; i < myNodelist.length; i++){
document.write (myNodelist[i] + "<br>");
}
</script>
</body>
</html>
Figure 10-2 shows what the output of Listing 10-3 looks like in a browser. Notice that the first child node of the section
element is a text node. If you look closely at the HTML markup in Listing 10-3, you'll see that there is a single space between the opening section
tag and the comment. Even something as simple as this single space creates an entire node in the DOM tree. This fact needs to be taken into consideration when you’re navigating the DOM using relationships between nodes.
The HTML DOM also provides a couple keywords for navigating nodes using their positions relative to their siblings or parents. The relative properties are
firstChild
: References the first child of a nodelastChild
: References the last child of the nodenextSibling
: References the next node with the same parent nodepreviousSibling
: References the previous node with the same parent nodeListing 10-4 shows how you can use these relative properties to traverse the DOM.
Listing 10-4: Using firstChild and lastChild to Highlight Navigation Links
<html>
<head>
<title>Iguanas Are No Fun</title>
<script>
function boldFirstAndLastNav() {
document.body.childNodes[1].firstChild.style.fontWeight="bold";
document.body.childNodes[1].lastChild.style.fontWeight="bold";
}
</script>
</head>
<body>
<nav><a href="home.html">Home</a> | <a href="why.html">Why Are Iguanas No Fun?</a> | <a href="what.html">What Can Be Done?</a> | <a href="contact.html">Contact Us</a></nav>
<p>Iguanas are no fun to be around. Use the links above to learn more.</p>
<script>
boldFirstAndLastNav();
</script>
</body>
</html>
Notice in Listing 10-4 that all the spacing must be removed between the elements within the <nav>
element in order for the firstChild
and lastChild
properties to access the correct elements that we want to select and style.
Figure 10-3 shows what the document in Listing 10-4 looks like when previewed in a browser. Notice that just the first and last links in the navigation are bold.
This is the first example in which we use the DOM to make a change to existing elements within the document. However, this method of selecting elements is almost never used. It’s too prone to mistakes and too difficult to interpret and use.
In the next section, you see that the DOM provides us with a much better means of traversing and manipulating the DOM than counting its children.
The Document
object provides properties and methods for working with HTML documents. The complete list of Document
object properties is shown in Table 10-1. The Document
object’s methods are shown in Table 10-2.
Table 10-1 The Document Object's Properties
Property |
Use |
|
Gets a list of all anchors ( |
|
Gets an ordered list of all the applets in the document |
|
Gets the base URI of the document |
|
Gets the |
|
Gets or sets the name/value pairs of cookies in the document |
|
Gets the Document Type Declaration associated with the document |
|
Gets the element that is the root of the document (for example, the |
|
Gets the mode used by the browser to render the document |
|
Gets or sets the location of the document |
|
Gets the domain name of the server that loaded the document |
|
Gets a list of all |
|
Gets a collection of all |
|
Gets the |
|
Gets a list of all |
|
Gets the |
|
Gets the date and time the current document was last modified |
|
Gets a collection of all |
|
Gets the loading status of the document. Returns |
|
Gets the URL of the page that the current document was linked from |
|
Gets a list of |
|
Gets or sets the title of the document |
|
Gets the full URL of the document |
Table 10-2 The Document Object's Methods
Method |
Use |
|
Assigns an event handler to the document |
|
Adopts a node from an external document |
|
Finishes the output writing stream of the document that was previously opened with |
|
Creates an attribute node |
|
Creates a comment node |
|
Creates an empty document fragment |
|
Creates an element node |
|
Creates a text node |
|
Gets the element that has the specified ID attribute |
|
Gets all elements with specified class name |
|
Gets all elements with the specified name |
|
Gets all elements with the specified tag name |
|
Copies and imports a node from an external document |
|
Clears the empty text nodes and joins adjacent nodes |
|
Opens a document for writing |
|
Gets the first element that matches the specified group of selector(s) in the document |
|
Gets a list of all the elements that match the specified selector(s) in the document |
|
Clears an event handler that had been added using the |
|
Renames an existing node |
|
Writes JavaScript code or HTML expressions to a document |
|
Writes JavaScript code or HTML expressions to a document and adds a new line character after each statement |
The Element
object provides properties and methods for working with HTML elements within a document. Table 10-3 shows all the properties of the Element
object. Table 10-4 lists all the methods of the Element
object.
Table 10-3 The Element Object's properties
Method |
Use |
|
Gets or sets the |
|
Gets a collection of all the element's attribute registered to the specified node (returns a |
|
Gets the number of child elements in the specified node |
|
Gets a list of the element's child nodes |
|
Gets a list of the element's child elements |
|
Gets the class name(s) of the element |
|
Gets or sets the value of the class attribute of the element |
|
Gets the inner height of an element, including padding |
|
Gets the left border width of the element |
|
Gets the top border width of the element |
|
Gets the width of the element, including padding |
|
Gets or sets whether the element is editable |
|
Gets or sets the value of the |
|
Gets the first child node of the element |
|
Gets the first child element of the element |
|
Gets or sets the value of the |
|
Gets or sets the content of the element |
|
Returns |
|
Gets or sets the base language of the elements attribute |
|
Gets the last child node of the element |
|
Gets the last child element of the element |
|
Gets the namespace URI for the first node in the element |
|
Gets the next node at the same node level |
|
Gets the next element at the same node level |
|
Gets the current node's name |
|
Gets the current node's type |
|
Gets or sets the value of the node |
|
Gets the height of the element, including vertical padding, borders, and scrollbar |
|
Gets the width of the element, including horizontal padding, borders, and scrollbar |
|
Gets the horizontal offset position of the element. |
|
Gets the offset container of the element |
|
Gets the vertical offset position of the element |
|
Gets the root element (document node) for an element |
|
Gets the parent node of the element |
|
Gets the parent element node of the element |
|
Gets the previous node at the same node tree level |
|
Gets the previous element node at the same node tree level |
|
Gets the entire height of the element, including padding |
|
Gets or sets the number of pixels the element's content is scrolled horizontally |
|
Gets or sets the number of pixels the element's content is scrolled vertically |
|
Gets the entire width of the element, including padding |
|
Gets or sets the value of the |
|
Gets or sets the value of the |
|
Gets the tag name of the element |
|
Gets or sets the textual content of the node and its descendants |
|
Gets or sets the value of the |
|
Gets the number of nodes in the |
Table 10-4 The Element Object’s Methods
Method |
Use |
|
Registers an event handler to the element |
|
Inserts a new child node to the element (as a last child node) |
|
Eliminates focus from the element |
|
Replicates a mouse-click on the element |
|
Clones the element |
|
Compares the document position of two elements |
|
Yields |
|
Gives focus to the element |
|
Gets the specified attribute value of the element node |
|
Gets the specified attribute node |
|
Gets a collection of all child elements with the stated class name. |
|
Gets a collection of all the child elements with the stated tag name |
|
Gets an object that implements the API's of the stated feature |
|
Yields |
|
Yields |
|
Yields |
|
Enters a new child node before the stated existing node |
|
Yields |
|
Evaluates to see whether two elements are equal |
|
Evaluates to see whether two elements are the same node |
|
Yields |
|
Joins the specified nodes with their adjacent nodes and removes any empty text nodes |
|
Gets the first child element that matches the stated CSS selector(s) of the element |
|
Gets all the child elements that match the stated CSS selector(s) of the element |
|
Takes the stated attribute out of the element |
|
Takes the stated attribute node out of the element and retrieves the removed node |
|
Removes the stated child node |
|
Replaces specified child node with another |
|
Removes the specified event handler |
|
Changes or sets the stated attribute to the specified value |
|
Changes or sets the stated attribute node |
|
Changes an element to a string |
|
Get the node at the stated index in the |
You can display node types and node values by using the HTML DOM. You also can set property values of elements within the DOM using the Element
object. When you use JavaScript to set the properties of DOM elements, the new values are reflected in real-time within the HTML document.
Changing the properties of elements in a web document in order to reflect them instantly in the browser, without needing to refresh or reload the web page, is a cornerstone of what used to be called Web 2.0.
The most important property of an element that you can modify through the DOM is the innerHTML
property.
The innerHTML
property of an element contains everything between the beginning and ending tag of the element. For example, in the following code, the innerHTML
property of the div
element contains a p
element and its text node child:
<body><div><p>This is some text.</p></div></body>
To retrieve and display the value of the innerHTML
property, you can use the following code:
var getTheInner = document.body.firstChild.innerHTML;
document.write (getTheInner);
In the preceding code, the value that will be output by the document.write()
method is
<p>This is some text.</p>
Setting the innerHTML
property is done in the same way that you set the property of any object:
document.body.firstChild.innerHTML = "Hi there!";
The result of running the preceding JavaScript will be that the p
element and the sentence of text in the original markup will be replaced with the words "Hi There!" The original HTML document remains unchanged, but the DOM representation and the rendering of the web page will be updated to reflect the new value. Because the DOM representation of the HTML document is what the browser displays, the display of your web page will also be updated.
To set the value of an HTML attribute, you can use the setAttribute()
method:
document.body.firstChild.innerHTML.setAttribute("class", "myclass");
The result of running this statement is that the first child element of the body element will be given a new attribute named "class"
with a value of "myclass"
.
The getElementBy
methods provide easy access to any element or groups of elements in a document without relying on parent/child relationships of nodes. The three most commonly used ways to access elements are
getElementById
getElementsByTagName
getElementsByClassName
By far the most widely used method for selecting elements, getElementById
is essential to modern web development. With this handy little tool, you can find and work with any element simply by referencing a unique id attribute. No matter what else happens in the HTML document, getElementById
will always be there for you and will reliably select the exact element that you want.
Listing 10-5 demonstrates the awesome power of getElementById
to enable you to keep all your JavaScript together in your document or to modularize your code. By using getElementById
, you can work with any element, anywhere in your document just as long as you know its id.
Listing 10-5: Using getElementById to Select Elements
<html>
<head>
<title>Using getElementById</title>
<script>
function calculateMPG(miles,gallons){
document.getElementById("displayMiles").innerHTML = parseInt(miles);
document.getElementById("displayGallons").innerHTML = parseInt(gallons);
document.getElementById("displayMPG").innerHTML = miles/gallons;
}
</script>
</head>
<body>
<p>You drove <span id="displayMiles">___</span> miles.</p>
<p>You used <span id="displayGallons">___</span> gallons of gas.</p>
<p>Your MPG is <span id="displayMPG">___</span>.
<script>
var milesDriven = prompt("Enter miles driven");
var gallonsGas = prompt("Enter the gallons of gas used");
calculateMPG(milesDriven,gallonsGas);
</script>
</body>
</html>
The getElementsByTagName
method returns a node list of all the elements with the specified tag name. For example, in Listing 10-6, getElementsByTagName
is used to select all h1
elements and change their innerHTML
properties to sequential numbers.
Listing 10-6: Using getElementsByTagName to Select and Change Elements
<html>
<head>
<title>Using getElementsByTagName</title>
<script>
function numberElements(tagName){
var getTags = document.getElementsByTagName(tagName);
for(i=0; i < getTags.length; i++){
getTags[i].innerHTML = i+1;
}
}
</script>
</head>
<body>
<h1>this text will go away</h1>
<h1>this will get overwritten</h1>
<h1>JavaScript will erase this</h1>
<script>
numberElements("h1");
</script>
</body>
</html>
The getElementsByClassName
method works in much the same way as the getElementsByTagName
, but it uses the values of the class attribute to select elements. The function in Listing 10-7 selects elements with a class of "error"
and will change the value of their innerHTML
property.
Listing 10-7: Using getElementsByClassName to Select and Change Elements
<html>
<head>
<title>Using getElementsByClassName</title>
<script>
function checkMath(result){
var userMath = document.getElementById("answer1").value;
var errors = document.getElementsByClassName("error");
if(parseInt(userMath) != parseInt(result)) {
errors[0].innerHTML = "That's wrong. You entered " + userMath + ". The answer is " + result;
} else {
errors[0].innerHTML = "Correct!";
}
}
</script>
</head>
<body>
<label for = "number1">4+1 = </label><input type="text" id="answer1" value="">
<button id="submit" onclick="checkMath(4+1);">Check your math!</button>
<h1 class="error"></h1>
</body>
</html>
The result of running Listing 10-7 in a web browser and entering a wrong answer is shown in Figure 10-4.
The Attribute
object provides properties for working with attributes within the HTML elements. Table 10-5 lists all the Attribute
object’s properties.
Table 10-5 The Attribute Object’s Properties
Property |
Use |
|
Yields |
|
Gets the name of the attribute |
|
Gets or sets the value of the attribute |
|
Yields |
To create a new element in an HTML document, use the document.createElement()
method. When you use createElement()
, a new beginning and end tag of the type you specify will be created.
Listing 10-8 shows an example of how you can use this method to dynamically create a list in an HTML document from an array.
Listing 10-8: Using document.createElement() to Generate a Table from an Array
<html>
<head>
<title>Generating a list</title>
</head>
<body>
<h1>Here are some types of balls</h1>
<ul id="ballList">
</ul>
<script>
var typeOfBall = ["basket", "base", "soccer", "foot", "hand"];
for (i=0; i<typeOfBall.length; i++) {
var listElement = document.createElement("li");
listElement.innerHTML = typeOfBall[i];
document.getElementById("ballList").appendChild(listElement);
}
</script>
</body>
</html>
For all the great things that it lets you do with HTML documents, the HTML DOM is not highly regarded by professional JavaScript programmers. It has a number of oddities and tends to make some things more difficult than they should be.
One of the big faults with the DOM is that it doesn’t provide any way to directly remove an element from a document. Instead, you have to tell the DOM to find the parent of the element you want to remove and then tell the parent to remove its child. It sounds a little confusing, but Listing 10-9 should clear it all up.
Listing 10-9: Removing an Element from a Document
<html>
<head>
<title>Remove an element</title>
<script>
function removeFirstParagraph(){
var firstPara = document.getElementById("firstparagraph");
firstPara.parentNode.removeChild(firstPara);
}
</script>
</head>
<body>
<div id="gibberish">
<p id="firstparagraph">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum molestie pulvinar ante, a volutpat est sodales et. Ut gravida justo ac leo euismod, et tempus magna posuere. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer non mi iaculis, facilisis risus et, vestibulum lorem. Sed quam ex, placerat nec tristique id, mattis fringilla ligula. Maecenas a pretium justo. Suspendisse sit amet nibh consectetur, tristique tellus quis, congue arcu. Etiam pellentesque dictum elit eget semper. Phasellus orci neque, semper ac tortor ac, laoreet ultricies enim.</p>
</div>
<button onclick="removeFirstParagraph();">That's Gibberish!</button>
</body>
</html>
When you run Listing 10-9 in a browser and press the button, the onclick
event calls the removeFirstParagraph()
function.
The first thing removeFirstParagraph()
does is to select the element that we actually want to remove, the element with the id = "firstparagraph".
Then, the script selects the parent node of the first paragraph. It then uses the removeChild()
method to remove the first paragraph.