Section 15.7. Modifying a Document


15.7. 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 15-5 includes a JavaScript function named sortkids(), a sample document, and an HTML button that, when pressed, calls the sortkids() function, passing it the ID of a <ul> tag. The sortkids() function finds the element children of the specified node, sorts them based on the text they contain, and rearranges them in the document (using appendChild()) so that they appear in alphabetical order.

Example 15-5. Alphabetizing the elements of a list

 <script> function sortkids(e) {      // This is the element whose children we are going to sort      if (typeof e == "string") e = document.getElementById(e);      // Transfer the element (but not text node) children of e to a real array      var kids = [];      for(var x = e.firstChild; x != null; x = x.nextSibling)          if (x.nodeType == 1 /* Node.ELEMENT_NODE */) kids.push(x);      // Now sort the array based on the text content of each kid.      // Assume that each kid has only a single child and it is a Text node      kids.sort(function(n, m) { // This is the comparator function for sorting                    var s = n.firstChild.data; // text of node n                    var t = m.firstChild.data; // text of node m                    if (s < t) return -1;      // n comes before m                    else if (s > t) return 1;  // n comes after m                    else return 0;             // n and m are equal                });      // Now append the kids back into the parent in their sorted order.      // When we insert a node that is already part of the document, it is      // automatically removed from its current position, so reinserting      // these nodes automatically moves them from their old position      // Note that any text nodes we skipped get left behind, however.      for(var i = 0; i < kids.length; i++) e.appendChild(kids[i]); } </script> <ul > <!-- This is the list we'll sort --> <li>one<li>two<li>three<li>four <!-- items are not in alphabetical order --> </ul> <!-- this is the button that sorts the list --> <button onclick="sortkids('list')">Sort list</button> 

The result of Example 15-5, illustrated in Figure 15-3, is that when the user clicks the button, the list items are alphabetized.

Figure 15-3. A list before and after being sorted


Note that Example 15-5 copied the nodes it was going to sort to a separate array. This enables you to easily sort the array but has another benefit as well. The NodeList objects that are the value of the childNodes property and that are returned by getElementsByTagName() are "live": any changes to the document are immediately reflected in the NodeList. This can be a source of difficulty if you insert or delete nodes from a list while iterating through that list. Thus it is often safest to take a "snapshot" of the nodes, by transferring them to a true array before looping through them.

Example 15-5 altered the structure of a document by rearranging elements. Example 15-6 alters the content of a document by changing its text. This example defines a function upcase() that recursively descends from a specified Node and converts the content of any Text nodes it finds to uppercase.

Example 15-6. Converting document content to uppercase

 // This function recursively looks at Node n and its descendants, // converting all Text node data to uppercase function upcase(n) {     if (n.nodeType == 3 /*Node.TEXT_NODE*/) {         // If the node is a Text node, change its text to uppercase.         n.data = n.data.toUpperCase();     }     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++) upcase(kids[i]);     } } 

Example 15-6 simply sets the data property of each text node it encounters. 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 Part IV.

In Example 15-5, you rearranged document elements but kept them within the same parent element. Note, however, that the DOM API allows nodes in the document tree to be moved freely within the tree (only within the same document, however). Example 15-7 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.

Example 15-7. Reparenting a node to a <b> element

 <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(n) {     if (typeof n == "string") n = document.getElementById(n); // Lookup node     var b = document.createElement("b"); // Create a new <b> element     var parent = n.parentNode;           // Get the parent of the node     parent.replaceChild(b, n);           // Replace the node with the <b> tag     b.appendChild(n);                    // Make the node a child of the <b> element } </script> <!-- A couple of sample paragraphs --> <p >This <i>is</i> paragraph #1.</p> <p >This <i>is</i> paragraph #2.</p> <!-- A button that invokes the embolden() function on the element named p1 --> <button onclick="embolden('p1');">Embolden</button> 

15.7.1. Modifying Attributes

In addition to modifying documents by altering text and reparenting or 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. 

As shown in Chapter 16, you can achieve a whole world of useful effects by altering the CSS style properties of HTML elements in this way. Doing so does not alter the document structure or content, but instead alters its presentation.

15.7.2. Working with Document Fragments

A DocumentFragment is a special type of node that does not appear in a document itself but serves as a temporary container for a sequential collection of nodes and allows those nodes to be manipulated as a single object. When a DocumentFragment is inserted into a document (using any of the appendChild(), insertBefore(), or replaceChild() methods of the Node object), it is not the DocumentFragment itself that is inserted, but each of its children.

You can create a DocumentFragment with document.createDocumentFragment(). You can add nodes to a DocumentFragment with appendChild() or any of the related Node methods. Then, when you are ready to add those nodes to the document, add the DocumentFragment itself. After you do this, the fragment is empty and cannot be reused unless you first add new children to it. Example 15-8 demonstrates this process. It defines a reverse() function that uses a DocumentFragment as a temporary container while reversing the order of the children of a Node.

Example 15-8. Using a DocumentFragment

 // Rever se the order of the children of Node n function reverse(n) {     // Create an empty DocumentFragment as a temporary container     var f = document.createDocumentFragment();     // Now loop backward through the children, moving each one to the fragment.     // The last child of n becomes the first child of f, and vice-versa.     // Note that appending a child to f automatically removes it from n.     while(n.lastChild) f.appendChild(n.lastChild);     // Finally, move the children of f all at once back to n, all at once.     n.appendChild(f); } 




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net