WebReference.com - Chapter 17 of JavaScript: The Definitive Guide (4th Ed), from O'Reilly & Associates (8/15) | WebReference

WebReference.com - Chapter 17 of JavaScript: The Definitive Guide (4th Ed), from O'Reilly & Associates (8/15)

To page 1To page 2To page 3To page 4To page 5To page 6To page 7current pageTo page 9To page 10To page 11To page 12To page 13To page 14To page 15
[previous] [next]

JavaScript: The Definitive Guide (4th Ed)

Modifying a Document

Traversing the nodes of a document can be useful, but the real power of the core DOM API lies in the features that allow you to use JavaScript to dynamically modify documents. The following examples demonstrate the basic techniques of modifying documents and illustrate some of the possibilities.

Example 17-3 includes a JavaScript function named reverse( ), a sample document, and an HTML button that, when pressed, calls the reverse( ) function, passing it the node that represents the <body> element of the document. (Note the use of getElementsByTagName( ) within the button's event handler to find the <body> element.) The reverse( ) function loops backward through the children of the supplied node and uses the removeChild( ) and appendChild( ) methods of the Node object to reverse the order of those children.

<head><title>Reverse</title>
<script>
function reverse(n) {           // Reverse the order of the children of Node n 
    var kids = n.childNodes;    // Get the list of children
    var numkids = kids.length;  // Figure out how many children there are
    for(var i = numkids-1; i >= 0; i--) {  // Loop backward through the children
        var c = n.removeChild(kids[i]);    // Remove a child
        n.appendChild(c);                  // Put it back at its new position
    }
}
</script>
</head>
<body>
<p>paragraph #1<p>paragraph #2<p>paragraph #3  <!-- A sample document -->
<p>                                    <!-- A button to call reverse(  )-->
<button onclick="reverse(document.body);"
>Click Me to Reverse</button>
</body>

Example 17-3: Reversing the nodes of a document

The result of Example 17-3, illustrated in Figure 17-3, is that when the user clicks the button, the order of the paragraphs and of the button are reversed.

A document before and after being reversed
Figure 17-3. A document before and after being reversed

There are a couple of points worth noting about Example 17-3. First, if you pass a node that is already part of the document to appendChild( ) it first removes it, so we could have simplified our code by omitting the call to removeChild( ). Second, keep in mind that the childNodes property (like all NodeList objects) is "live": when the document is modified, the modifications are immediately visible through the NodeList. This is an important features of the NodeList interface, but it can actually make some code trickier to write. A call to removeChild( ), for example, changes the index of all the siblings that follow that child, so if you want to iterate through a NodeList and delete some of the nodes, you must write your looping code carefully.

Example 17-4 shows a variation on the reverse( ) function of the previous example. This one uses recursion to reverse not only the children of a specified node, but also all the node's descendants. In addition, when it encounters a Text node, it reverses the order of the characters within that node. Example 17-4 shows only the JavaScript code for this new reverse( ) function. It could easily be used in an HTML document like the one shown in Example 17-3, however.

// Recursively reverse all nodes beneath Node n and reverse Text nodes
function reverse(n) { 
    if (n.nodeType == 3 /*Node.TEXT_NODE*/) {    // Reverse Text nodes
        var text = n.data;                       // Get content of node
        var reversed = "";
        for(var i = text.length-1; i >= 0; i--)  // Reverse it
            reversed += text.charAt(i);
        n.data = reversed;                       // Store reversed text
    }
    else {  // For non-Text nodes, recursively reverse the order of the children
        var kids = n.childNodes;
        var numkids = kids.length;
        for(var i = numkids-1; i >= 0; i--) {       // Loop through kids
            reverse(kids[i]);                       // Recurse to reverse kid
            n.appendChild(n.removeChild(kids[i]));  // Move kid to new position
        }
    }
}

Example 17-4: A recursive node-reversal function

Example 17-4 shows one way to change the text displayed in a document: simply set the data field of the appropriate Text node. Example 17-5 shows another way. This example defines a function, uppercase( ), that recursively traverses the children of a given node. When it finds a Text node, the function replaces that node with a new Text node containing the text of the original node, converted to uppercase. Note the use of the document.createTextNode( ) method to create the new Text node and the use of Node's replaceChild( ) method to replace the original Text node with the newly created one. Note also that replaceChild( ) is invoked on the parent of the node to be replaced, not on the node itself. The uppercase( ) function uses Node's parentNode property to determine the parent of the Text node it replaces.

In addition to defining the uppercase( ) function, Example 17-5 includes two HTML paragraphs and a button. When the user clicks the button, one of the paragraphs is converted to uppercase. Each paragraph is identified with a unique name, specified with the id attribute of the <p> tag. The event handler on the button uses the getElementById( ) method to get the Element object that represents the desired paragraph.

<script>
// This function recursively looks at Node n and its descendants, 
// replacing all Text nodes with their uppercase equivalents.
function uppercase(n) {
    if (n.nodeType == 3 /*Node.TEXT_NODE*/) {
        // If the node is a Text node, create a new Text node that
        // holds the uppercase version of the node's text, and use the
        // replaceChild(  ) method of the parent node to replace the
        // original node with the new uppercase node.
        var newNode = document.createTextNode(n.data.toUpperCase(  ));
        var parent = n.parentNode;
        parent.replaceChild(newNode, n);
    }
    else {
        // If the node is not a Text node, loop through its children
        // and recursively call this function on each child.
        var kids = n.childNodes;
        for(var i = 0; i < kids.length; i++) uppercase(kids[i]);
    }
}
</script>
 
<!-- Here is some sample text. Note that the <p> tags have id attributes. -->
<p id="p1">This <i>is</i> paragraph 1.</p>
<p id="p2">This <i>is</i> paragraph 2.</p>
 
<!-- Here is a button that invokes the uppercase(  ) function defined above. -->
<!-- Note the call to document.getElementById(  ) to find the desired node. -->
<button onclick="uppercase(document.getElementById('p1'));">Click Me</button> 

Example 17-5: Replacing nodes with their uppercase equivalents

The previous two examples show how to modify document content by replacing the text contained within a Text node and by replacing one Text node with an entirely new Text node. It is also possible to append, insert, delete, or replace text within a Text node with the appendData( ), insertData( ), deleteData( ), and replaceData( ) methods. These methods are not directly defined by the Text interface, but instead are inherited by Text from CharacterData. You can find more information about them under "CharacterData" in the DOM reference section.

In the node-reversal examples, we saw how we could use the removeChild( ) and appendChild( ) methods to reorder the children of a Node. Note, however, that we are not restricted to changing the order of nodes within their parent node; the DOM API allows nodes in the document tree to be moved freely within the tree (only within the same document, however). Example 17-6 demonstrates this by defining a function named embolden( ) that replaces a specified node with a new element (created with the createElement( ) method of the Document object) that represents an HTML <b> tag and "reparents" the original node as a child of the new <b> node. In an HTML document, this causes any text within the node or its descendants to be displayed in boldface.

<script>
// This function takes a Node n, replaces it in the tree with an Element node
// that represents an HTML <b> tag, and then makes the original node the
// child of the new <b> element.
function embolden(node) {
    var bold = document.createElement("b");  // Create a new <b> element
    var parent = node.parentNode;            // Get the parent of the node
    parent.replaceChild(bold, node);         // Replace the node with the <b> tag
    bold.appendChild(node);                  // Make the node a child of the <b> tag
}
</script>
 
<!-- A couple of sample paragraphs -->
<p id="p1">This <i>is</i> paragraph #1.</p>
<p id="p2">This <i>is</i> paragraph #2.</p>
 
<!-- A button that invokes the embolden(  ) function on the first paragraph -->
<button onclick="embolden(document.getElementById('p1'));">Embolden</button>

Example 17-6: Reparenting a node to a <b> element

In addition to modifying documents by inserting, deleting, reparenting, and otherwise rearranging nodes, it is also possible to make substantial changes to a document simply by setting attribute values on document elements. One way to do this is with the element.setAttribute( ) method. For example:

var headline = document.getElementById("headline");  // Find named element
headline.setAttribute("align", "center");            // Set align='center' 

The DOM elements that represent HTML attributes define JavaScript properties that correspond to each of their standard attributes (even deprecated attributes such as align), so you can also achieve the same effect with this code:

var headline = document.getElementById("headline");
headline.align = "center";  // Set alignment attribute. 

To page 1To page 2To page 3To page 4To page 5To page 6To page 7current pageTo page 9To page 10To page 11To page 12To page 13To page 14To page 15
[previous] [next]

Created: November 28, 2001
Revised: November 28, 2001

URL: http://webreference.com/programming/javascript/definitive/chap17/8.html