Section 15.6. Finding Elements in a Document


15.6. Finding Elements in a Document

The ability to traverse all nodes in a document tree gives you the power to find specific nodes. When programming with the DOM API, it is quite common to need a particular node within the document or a list of nodes of a specific type within the document. Fortunately, the DOM API provides functions that make this easy.

The Document object is the root of every DOM tree, but it does not represent an HTML element in that tree. The document.documentElement property refers to the <html> tag that serves as the root element of the document. And the document.body property refers to the <body> tag which is more commonly useful than its <html> parent.

The body property of the HTMLDocument object is a convenient special-case property. If it did not exist, however, you could also refer to the <body> tag like this:

 document.getElementsByTagName("body")[0] 

This expression calls the Document object's getElementsByTagName() method and selects the first element of the returned array. The call to getElementsByTagName() returns an array of all <body> elements within the document. Since HTML documents can have only one <body>, you're interested in the first element of the returned array.[*]

[*] Technically, getElementsByTagName() returns a NodeList, which is an array-like object. In this book, I use array notation for indexing them and informally refer to them as "arrays."

You can use getElementsByTagName() to obtain a list of any type of HTML element. For example, to find all the tables within a document, you'd do this:

 var tables = document.getElementsByTagName("table"); alert("This document contains " + tables.length + " tables"); 

Note that since HTML tags are not case-sensitive, the strings passed to getElementsByTagName() are also not case-sensitive. That is, the previous code finds <table> tags even if they are coded as <TABLE>. getElementsByTagName() returns elements in the order in which they appear in the document. Finally, if you pass the special string "15-" to getElementsByTagName(), it returns a list of all elements in the document, in the order in which they appear. (This special usage is not supported in IE 5 and IE 5.5. See instead the IE-specific HTMLDocument.all[] in Part IV.)

Sometimes you don't want a list of elements but instead want to operate on a single specific element of a document. If you know a lot about the structure of the document, you may still be able to use getElementsByTagName(). For example, if you want to do something to the fourth paragraph in a document, you might use this code:

 var myParagraph = document.getElementsByTagName("p")[3]; 

This typically is not the best (nor the most efficient) technique, however, because it depends so heavily on the structure of the document; a new paragraph inserted at the beginning of the document would break the code. Instead, when you need to manipulate specific elements of a document, it is best to give those elements an id attribute that specifies a unique (within the document) name for the element. You can then look up your desired element by its ID. For example, you might code the special fourth paragraph of your document with a tag like this:

 <p > 

You can then look up the node for that paragraph with JavaScript code like this:

 var myParagraph = document.getElementById("specialParagraph"); 

Note that the getElementById() method does not return an array of elements as getElementsByTagName() does. Because the value of every id attribute is (or is supposed to be) unique, getElementById() returns only the single element with the matching id attribute.

getElementById() is an important method, and its use is extremely common in DOM programming. It is so commonly used that you may want to define a utility function with a shorter name. For example:

 // If x is a string, assume it is an element id and look up the named element. // Otherwise, assume x is already an element and just return it. function id(x) {     if (typeof x == "string") return document.getElementById(x);     return x; } 

With a function like this defined, your DOM manipulation methods can be written to accept elements or element IDs as their arguments. For each such argument x, simply write x = id(x) before use. One well-known client-side JavaScript toolkit[*] defines a utility method like this but gives it an even shorter name: $().

[*] The Prototype library by Sam Stephenson, available from http://prototype.conio.net.

getElementById() and getElementsByTagName() are both methods of the Document object. Element objects also define a getElementsByTagName() method, however. This method of the Element object behaves just like the method of the Document object, except that it returns only elements that are descendants of the element on which it is invoked. Instead of searching the entire document for elements of a specific type, it searches only within the given element. This makes it possible, for example, to use getElementById() to find a specific element and then to use getElementsByTagName() to find all descendants of a given type within that specific tag. For example:

 // Find a specific Table element within a document and count its rows var tableOfContents = document.getElementById("TOC"); var rows = tableOfContents.getElementsByTagName("tr"); var numrows = rows.length; 

Finally, note that for HTML documents, the HTMLDocument object also defines a getElementsByName() method. This method is like getElementById(), but it looks at the name attribute of elements rather than the id attribute. Also, because the name attribute is not expected to be unique within a document (for example, radio buttons within HTML forms usually have the same name), getElementsByName() returns an array of elements rather than a single element. For example:

 // Find <a name="top"> var link = document.getElementsByName("top")[0]; // Find all <input type="radio" name="shippingMethod"> elements var choices = document.getElementsByName("shippingMethod"); 

In addition to selecting document elements by tag name or ID, it is also often useful to select elements that are members of a class. The HTML class attribute and the corresponding JavaScript className property assign an element to one or more named (and whitespace delimited) classes. These classes are intended for use with CSS stylesheets (see Chapter 16) but that need not be their only purpose. Suppose you code important warnings in an HTML document like this:

 <div > This is a warning </div> 

You can then use a CSS stylesheet to specify the colors, margins, borders, and other presentational attributes of those warnings. But what if you also wanted to write JavaScript code that could find and operate on <div> tags that are members of the "warning" class? Example 15-4 has a solution. This example defines a getElements() method that allows you to select elements by class and/or tag name. Note that the className property is a tricky one because an HTML element can be a member of more than one class. getElements() includes a nested isMember() method that tests whether a specified HTML element is a member of a specified class.

Example 15-4. Selecting HTML elements by class or tag name

 /**  * getElements(classname, tagname, root):  * Return an array of DOM elements that are members of the specified class,  * have the specified tagname, and are descendants of the specified root.  *  * If no classname is specified, elements are returned regardless of class.  * If no tagname is specified, elements are returned regardless of tagname.  * If no root is specified, the document object is used. If the specified  * root is a string, it is an element id, and the root  * element is looked up using getElementsById()  */ function getElements(classname, tagname, root) {     // If no root was specified, use the entire document     // If a string was specified, look it up     if (!root) root = document;     else if (typeof root == "string") root = document.getElementById(root);     // if no tagname was specified, use all tags     if (!tagname) tagname = "15-";     // Find all descendants of the specified root with the specified tagname     var all = root.getElementsByTagName(tagname);     // If no classname was specified, we return all tags     if (!classname) return all;     // Otherwise, we filter the element by classname     var elements = [];  // Start with an empty array     for(var i = 0; i < all.length; i++) {         var element = all[i];         if (isMember(element, classname)) // isMember() is defined below             elements.push(element);       // Add class members to our array     }     // Note that we always return an array, even if it is empty     return elements;     // Determine whether the specified element is a member of the specified     // class. This function is optimized for the common case in which the     // className property contains only a single classname. But it also     // handles the case in which it is a list of whitespace-separated classes.     function isMember(element, classname) {         var classes = element.className;  // Get the list of classes         if (!classes) return false;             // No classes defined         if (classes == classname) return true;  // Exact match         // We didn't match exactly, so if there is no whitespace, then         // this element is not a member of the class         var whitespace = /\s+/;         if (!whitespace.test(classes)) return false;         // If we get here, the element is a member of more than one class and         // we've got to check them individually.         var c = classes.split(whitespace);  // Split with whitespace delimiter         for(var i = 0; i < c.length; i++) { // Loop through classes             if (c[i] == classname) return true;  // and check for matches         }         return false;  // None of the classes matched     } } 




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