<!- -

14. Using Advanced DOM Features

wax ka badal

Working with DOM Nodes

wax ka badal

As you learned in [Hour 13], "Using the W3C DOM," the DOM organizes objects within a web page into a tree-like structure. Each node (object) in this tree can be accessed in JavaScript. In the next sections you will learn how you can use the properties and methods of nodes to manage them.

By the Way
The following sections only describe the most important properties and methods of nodes, and those that are supported by current browsers. For a complete list of available properties, see the W3C's DOM specification at http://www.w3.org/TR/DOM-Level-2/.

Basic Node Properties

wax ka badal

You have already used the style property of nodes to change their style sheet values. Each node also has a number of basic properties that you can examine or set. These include the following:

  • nodeName is the name of the node (not the ID). For nodes based on HTML tags, such as <p> or <body>, the name is the tag name: P or BODY. For the document node, the name is a special code: #document. Similarly, text nodes have the name #text.
  • nodeType is an integer describing the node's type: 1 for normal HTML tags, 3 for text nodes, and 9 for the document node.
  • nodeValue is the actual text contained within a text node. This property is not valid for other types of nodes.
  • innerHTML is the HTML content of any node. You can assign a value including HTML tags to this property and change the DOM child objects for a node dynamically.
By the Way
The innerHTML property is not a part of the W3C DOM specification. However, it is supported by the major browsers, and is often the easiest way to change content in a page. You can also accomplish this in a more standard way by deleting and creating nodes, as described later in this hour.

Node Relationship Properties

wax ka badal

In addition to the basic properties described previously, each node has a number of properties that describe its relation to other nodes. These include the following:

  • firstChild is the first child object for a node. For nodes that contain text, such as h1 or p, the text node containing the actual text is the first child.
  • lastChild is the node's last child object.
  • childNodes is an array that includes all of a node's child nodes. You can use a loop with this array to work with all the nodes under a given node.
  • previousSibling is the sibling (node at the same level) previous to the current node.
  • nextSibling is the sibling after the current node.
Watch Out
Remember that, like all JavaScript objects and properties, the node properties and functions described here are case sensitive. Be sure you type them exactly as shown.

Document Methods

wax ka badal

The document node itself has several methods you might find useful. You have already used one of these, getElementById(), to refer to DOM objects by their ID properties. The document node's methods include the following:

  • getElementById(id) returns the element with the specified id attribute.
  • getElementsByTagName(tag) returns an array of all of the elements with a specified tag name. You can use the wildcard * to return an array containing all the nodes in the document.
  • createTextNode(text) creates a new text node containing the specified text, which you can then add to the document.
  • createElement(tag) creates a new HTML element for the specified tag. As with createTextNode, you need to add the element to the document after creating it. You can assign content within the element by changing its child objects or the innerHTML property.

Node Methods

wax ka badal

Each node within a page has a number of methods available. Which of these are valid depends on the node's position in the page, and whether it has parent or child nodes. These include the following:

  • appendChild(new) appends the specified new node after all of the object's existing nodes.
  • insertBefore(new, old) inserts the specified new child node before the specified old child node, which must already exist.
  • replaceChild(new, old) replaces the specified old child node with a new node.
  • removeChild(node) removes a child node from the object's set of children.
  • hasChildNodes() returns a Boolean value of true if the object has one or more child nodes, or false if it has none.
  • cloneNode() creates a copy of an existing node. If a parameter of true is supplied, the copy will also include any child nodes of the original node.

Hiding and Showing Objects

wax ka badal

We will now move on to a number of real-world examples using the DOM objects to manipulate web pages. As a simple example, you can create a script that hides or shows objects within a page.

As you learned in [Hour 13], objects have a visibility style property that specifies whether they are currently visible within the page:

Object.style.visibility="hidden"; // hides an object
Object.style.visibility="visible"; // shows an object

Using this property, you can create a script that hides or shows objects in either browser. [Listing 14.1] shows the HTML document for a script that allows two headings to be shown or hidden.

Listing 14.1. Hiding and Showing Objects
<html>
<head>
<title>Hiding and Showing Objects</title>
<script language="Javascript" type="text/javascript">
function ShowHide() {
if (!document.getElementById) return;
var head1 = document.getElementById("head1");
var head2 = document.getElementById("head2");
var showhead1 = document.form1.head1.checked;
var showhead2 = document.form1.head2.checked;
head1.style.visibility=(showhead1) ? "visible" : "hidden";
head2.style.visibility=(showhead2) ? "visible" : "hidden";
}
</script>
</head>
<body>
<h1 ID="head1">This is the first heading</h1>
<h1 ID="head2">This is the second heading</h1>
<p>Using the W3C DOM, you can choose
whether to show or hide the headings on
this page using the checkboxes below.</p>
<form name="form1">
<input type="checkbox" name="head1"
checked onClick="ShowHide();">
<b>Show first heading</b><br>
<input type="checkbox" name="head2"
checked onClick="ShowHide();">
<b>Show second heading</b><br>
</form>
</body>
</html>

The <h1> tags in this document define headings with the identifiers head1 and head2. The <form> section defines a form with two check boxes, one for each of the headings. When a check box is modified, the onClick method is used to call the ShowHide() function.

This function is defined within the <script> statements in the header. The function assigns the head1 and head2 variables to the objects for the headings, using the getElementById() method. Next, it assigns the showhead1 and showhead2 variables to the contents of the check boxes. Finally, the function uses the style.visibility attributes to set the visibility of the headings.

Did you Know?
The lines that set the visibility property might look a bit strange. The ? and : characters create conditional expressions, a shorthand way of handling if statements. To review conditional expressions, see [Hour 7], "Controlling Flow with Conditions and Loops."

[Figure 14.1] shows this example in action in Internet Explorer. In the figure, the second heading's check box has been unchecked, so only the first heading is visible.

Modifying Text Within a Page

wax ka badal

Next, you can create a simple script to modify the contents of a heading within a web page. As you learned earlier this hour, the nodeValue property of a text node contains its actual text, and the text node for a heading is a child of that heading. Thus, the syntax to change the text of a heading with the identifier head1 would be

Var head1 = document.getElementById("head1");
Head1.firstChild.nodeValue = "New Text Here";

This assigns the variable head1 to the heading's object. The firstChild property returns the text node that is the only child of the heading, and its nodeValue property contains the heading text.

Using this technique, it's easy to create a page that allows the heading to be changed dynamically. [Listing 14.2] shows the complete HTML document for this script.

Listing 14.2. The Complete Text-Modifying Example
<html>
<head>
<title>Dynamic Text in JavaScript</title>
<script language="Javascript" type="text/javascript">
function ChangeTitle() {
if (!document.getElementById) return;
var newtitle = document.form1.newtitle.value;
var head1 = document.getElementById("head1");
head1.firstChild.nodeValue=newtitle;
}
</script>
</head>
<body>
<h1 ID="head1">Dynamic Text in JavaScript</h1>
<p>Using the W3C DOM, you can dynamically
change the heading at the top of this
page. Enter a new title and click the
Change button.</p>
<form name="form1">
<input type="text" name="newtitle" size="25">
<input type="button" value="Change!"
onClick="ChangeTitle();">
</form>
</body>
</html>

This example defines a form that allows the user to enter a new heading for the page. Pressing the button calls the ChangeTitle() function, defined in the header. This function gets the value the user entered in the form, and changes the heading's value to the new text.

[Figure 14.2] shows this page in action in Internet Explorer after a new title has been entered and the Change button has been clicked.

Adding Text to a Page

wax ka badal

Next, you can create a script that actually adds text to a page. To do this, you must first create a new text node. This statement creates a new text node with the text "this is a test":

var node=document.createTextNode("this is a test");

Next, you can add this node to the document. To do this, you use the appendChild method. The text can be added to any element that can contain text, but we will use a paragraph. The following statement adds the text node defined previously to the paragraph with the identifier p1:

document.getElementById("p1").appendChild(node);

[Listing 14.3] shows the HTML document for a complete example that uses this technique, using a form to allow the user to specify text to add to the page.

Listing 14.3. Adding Text to a Page
<html>
<head>
<title>Adding to a page</title>
<script language="Javascript" type="text/javascript">
function AddText() {
if (!document.getElementById) return;
var sentence=document.form1.sentence.value;
var node=document.createTextNode(" " + sentence);
document.getElementById("p1").appendChild(node);
document.form1.sentence.value="";
}
</script>
</head>
<body>
<h1>Create Your Own Content</h1>
<p id="p1">Using the W3C DOM, you can dynamically
add sentences to this paragraph. Type a sentence
and click the Add button.</p>
<form name="form1">
<input type="text" name="sentence" size="65">
<input type="button" value="Add" onClick="AddText();">
</form>
</body>
</html>

In this example, the <p> section defines the paragraph that will hold the added text. The <form> section defines a form with a text field called sentence, and an Add button, which calls the AddText() function. This function is defined in the header.

The AddText() function first assigns the sentence variable to the text typed in the text field. Next, it creates a new text node containing the sentence, and appends the new text node to the paragraph.

Load this document into a browser to test it, and try adding several sentences by typing them and clicking the Add button. [Figure 14.3] shows Firefox's display of this document after several sentences have been added to the paragraph.

Try It Yourself — Creating a Navigation Tree

wax ka badal

One common use of JavaScript and the DOM is to create a dynamic tree-like navigation system for a site, with sections that can be expanded and collapsed. Although this is unnecessary for small sites, it's a good way to organize what may be hundreds of links for a larger site. To further experiment with the techniques you learned about in this hour, you can create a simple navigation tree using the DOM.

To begin, you will need an HTML document that defines the content of the navigation tree, shown in [Listing 14.4].

Listing 14.4. The HTML for the Navigation Tree Example
<html>
<head><title>Creating a Navigation Tree</title>
<style>
A {text-decoration: none;}

# productsmenu,#supportmenu,#contactmenu {

display: none;
margin-left: 2em;
}
</style>
</head>
<body>
<h1>Navigation Tree Example</h1>
<p>The navigation tree below allows you to expand and
collapse items.</p>
<ul>
<li><a id="products" href="#">[+] Products</a>
<ul ID="productsmenu">
<li><a href="prodlist.html">Product List</a></li>
<li><a href="order.html">Order Form</a></li>
<li><a href="pricelist.html">Price List</a></li>
</ul>
</li>
<li><a id="support" href="#">[+] Support</a>
<ul id="supportmenu">
<li><a href="sforum.html">Support Forum</a></li>
<li><a href="scontact.html">Contact Support</a></li>
</ul>
</li>
<li><a ID="contact" href="#">[+] Contact Us</a>
<ul id="contactmenu">
<li><a href="contact1.html">Service Department</a></li>
<li><a href="contact2.html">Sales Department</a></li>
</ul>
</li>
</ul>
<script language="javascript" type="text/javascript"
src="tree.js">
</script>
</body>
</html>

In this document, the links are laid out as a nested list using <ul> and <li> tags. Using a standard list like this rather than tags has two benefits: First, the browser formats the tree as a list with bullets automatically. Second, it supports older browser—seven a browser that does not support CSS or JavaScript will load and display the list correctly. It won't have the dynamic features, but the links will still work.

The tree has three main nodes: Products, Support, and Contact Us. Each one has a link you can click to display or hide the links in that section. The id attribute has been used on each <a> tag so the script can attach an event handler to it. Each node also has a submenu defined with <ul> and <li> tags. An id attribute is also used on the <ul> tag so the script can hide or display the list.

The <script> tag at the end of the document includes the script you will create next. The tag is placed after the body of the page so that the script can add event handlers to elements in the page.

The <style> block at the beginning of the document adds some formatting to the links, and uses the display: none attribute to initially hide the submenus. They will be revealed by the script when the link is clicked.

The script for this example is shown in [Listing 14.5].

Listing 14.5. The JavaScript File for the Navigation Tree Example
function Toggle(e) {
// Don't try this in old browsers
if (!document.getElementById) return;
// Get the event object
if (!e) var e = window.event;
// Which link was clicked?
whichlink = (e.target) ? e.target.id : e.srcElement.id;
// get the menu object
obj=document.getElementById(whichlink+"menu");
// Is the menu visible?
visible=(obj.style.display=="block")
// Get the key object (the link itself)
key=document.getElementById(whichlink);
// Get the name (Products, Contact, etc.)
keyname = key.firstChild.nodeValue.substring(3);
if (visible) {
// hide the menu
obj.style.display="none";
key.firstChild.nodeValue = "[+]" + keyname;
} else {
// show the menu
obj.style.display="block";
key.firstChild.nodeValue = "[-]" + keyname;
}
}
document.getElementById("products").onclick=Toggle;
document.getElementById("support").onclick=Toggle;
document.getElementById("contact").onclick=Toggle;

The Toggle() function shows or hides a menu. It first determines which of the links triggered the event, and then uses the link's id attribute to find the objects for the menu and for the link itself. If the menu is currently visible, it is hidden, and if it is currently hidden, it is revealed. The appropriate symbol [+] or [-] is added to the link name and displayed by modifying the text node's nodeValue attribute.

The last three lines of the script assign the Toggle() function as the onClick event handler for the three top-level links of the tree.

To use this script, save it as tree.js in the same folder as the HTML document you created previously, and load the HTML file into a browser. [Figure 14.4] shows the example in action after all three nodes of the tree have been expanded.

Did you Know?
To add items to the navigation tree, add links to the HTML file. If you add a new submenu, you need to assign an id attribute to the link, use the same word plus menu as the id of the menu, and assign its onclick event to the Toggle() function at the end of the script.

In this hour, you learned some of the advanced features of the new W3C DOM (Document Object Model). You learned the functions and properties you can use to manage DOM objects, and used example scripts to hide and show elements within a page, modify text, and add text. Finally, you created a dynamic navigation tree using DOM features.

Congratulations—you've reached the end of Part III! Now that you've learned all about the DOM, you will move on to some advanced aspects of JavaScript. In the next hour, you will learn how to create scripts that unobtrusively handle multiple browsers, and some best practices for more involved scripting.

Q1: Can I avoid assigning an id attribute to every DOM object I want to handle with a script?

A1: Yes. Although the scripts in this hour typically use the id attribute for convenience, you can actually locate any object in the page by using combinations of node properties such as firstChild and nextSibling. However, keep in mind that any change you make to the HTML can change an element's place in the DOM hierarchy, so the id attribute is a reliable way to handle this.


Q2: Can I include HTML tags, such as <b>, in the new text I assign to a text node?

A2: Text nodes are limited to text if you use the nodeValue attribute. However, the innerHTML property does not have this limitation and can be used to insert any HTML.

Q3: Is there a reference that specifies which DOM properties and methods work in which browser versions?

A3: Yes, several websites are available that keep up-to-date lists of browser features. Some of these are listed in [Appendix A], "Other JavaScript Resources."

Quiz Questions

wax ka badal

Test your knowledge of the DOM by answering the following questions.


1. If para1 is the DOM object for a paragraph, what is the correct syntax to change the text within the paragraph to "New Text"?

  1. para1.value="New Text";
  2. para1.firstChild.nodeValue="New Text";
  3. para1.nodeValue="New Text";


2. Which of the following DOM objects never has a parent node?

  1. body
  2. div
  3. document


3. Which of the following is the correct syntax to get the DOM object for a heading with the identifier head1?

  1. document.getElementById("head1")
  2. document.GetElementByID("head1")
  3. document.getElementsById("head1")


Quiz Answers

wax ka badal

1. b. The actual text is the nodeValue attribute of the text node, which is a child of the paragraph node.

2. c. The document object is the root of the DOM object tree, and has no parent object.

3. a. getElementById has a lowercase g at the beginning, and a lowercase d at the end, contrary to what you might know about normal English grammar.


If you want to gain more experience using the advanced DOM features you learned in this hour, try the following exercise:

  • Add a third check box to [Listing 14.1] to allow the paragraph of text to be shown or hidden. You will need to add an id attribute to the <p> tag, add a check box to the form, and add the appropriate lines to the script.
  • Add a fourth node to the navigation tree in [Listing 14.4], and make the appropriate changes to the script in [Listing 14.5] to make the new section of the tree expand and collapse correctly.