Eight Weeks of Prototype: Week 1, Beginning with Prototype
DOM Traversal Methods
In addition to being able to select elements in the DOM using
select(), Prototype also allows you to select elements using the
down(), next() and
previous() methods. These methods help you to easily find elements relative to a given element.
select(), each of these methods is used to retrieve exactly one element (if found). Because of this (and because each element is returned with the extended Prototype functionality), you can chain these calls together, as you will see at the end of this section.
The up() method
To find an element further up the DOM tree from a given element (that is, to find one of its ancestors) you can use the
up() method. If no arguments are passed to
up(), then the element's parent is returned.
If you don't just want an element's parent element but rather one of its other ancestors there are several different combinations of arguments that can be used. Firstly, you can specify a numerical index. For instance, using
up(0) will retrieve the element's parent (the same as omitting the argument), using
up(1) will return the element's grandparent, and using
up(2) will return the great-grandparent.
Alternatively, you can pass a CSS selector to
up(). The first matched element is returned. For example, if you have an image inside a HTML table (e.g.
<table><tr><td> <img /> </td></tr></table>), you can use
imgElt.up('table') to retrieve the table element (in this case using just
imgElt.up() might return the
<td> element instead).
You can also specify a numerical index along with a CSS selector. For example, if you have an image within two nested div elements, you can select the outer div by using
imgElt.up('div', 1) (the first element from the target has an index of
0, which is the default value if the second argument isn't specified).
Listing 7 shows some examples of how to use the
up() method to find an element's ancestors.
One of the most useful aspects of
up() is that you can easily find an element without caring which elements lie between the element you want to find and the element you're searching on. That is, because you can use selectors to find the parent, you don't mind whether the element is the parent, the grandparent or otherwise.
The down() method
down() method is the opposite of the
up() method, in that it searches within an element's descendants rather than in its ancestors. That is, it looks for elements within the target element.
up(), you can either specify no arguments, a numerical index, a CSS selector, or a CSS selector with a numerical index. Specifying no arguments will result in the first child being returned.
down() is very similar to using the
select() method covered earlier in this article, except that only a single element is returned using
down() (remember that
select() returns an array). Because of this, we can deduce that
someElt.down('.foo') is effectively equivalent to
The important difference is that trying to reference an particular element when using
select() call returns an empty array. This is not an issue when using
Listing 8 shows some examples of using
down() to find an element's descendants.
The next() and previous() methods
You can find sibling elements (that is, any element with the same parent element as the search target) using the next() and
previous() methods. As suggested by their names, next() finds siblings elements that appear in the document after the search target, while
previous() finds only siblings that appear before the search target.
The arguments used for next() and
previous() work in the same manner as with
down(). That is, you can use a numerical index or a CSS selector.
Listing 9 shows several examples of using next() and
Chaining traversal calls together
Because calls to
down(), next() and
previous() each return a single element that has been extended with extra Prototype functionality, we can chain calls to these functions together.
For example, calling
elt.down().up() will return the original element
elt (note, however, that calling
elt.up().down() will not necessarily return the original element; this will depend on the ordering of elements within
elt's parent). Similarly,
elt.next().previous() will also return
Obviously there is little use for these examples in particular, however you may encounter situations where chaining these calls together is extremely useful. One such example might be to search all siblings of an element. Using
elt.next(someSelector) only finds siblings before the given element, while
elt.previous(someSelector) only finds siblings after the element. If you wanted to search either before or after, you could do so by using
When chaining calls together, there is a risk that one of the later calls in the chain may cause an error due to an earlier call not returning an element (for instance, calling
previous() on an element with no siblings will not return a valid element). Because of this, you should only chain your calls together when you know it cannot fail. Otherwise, you should make each call in a separate statement and check the return values accordingly.