<html>
<head>
<title>Using select() to search for elements within a given elementtitle>
<script type="text/javascript" src="/js/prototype.js">script>
head>
<body>
<div>
<ul id="someElement">
<li>li>
<li>li>
<li>li>
ul>
div>
<div id="exampleDiv">div>
<script type="text/javascript">
var elt = $('someElement');
var items = elt.select('li');
for (var i = 0; i < items.size(); i++) {
items[i].update('Element ' + i);
}
script>
body>
html>
DOM Traversal Methods
In addition to being able to select elements in the DOM using $$() and select(), Prototype also allows you to select elements using the up(), down(), next() and previous() methods. These methods help you to easily find elements relative to a given element.
Unlike $$() and 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.
), you can use imgElt.up('table') to retrieve the table element (in this case using just imgElt.up() might return the 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.
Listing 7 Examples of using up() to find an element's ancestors (listing-7.html)
<html>
<head>
<title>Examples of using up() to find an element's ancestorstitle>
<script type="text/javascript" src="/js/prototype.js">script>
head>
<body>
<div id="main" class="foo">
<table class="foo">
<tr>
<td>
<a href="#"><img src="someImage.png" id="someImage" />a>
td>
tr>
table>
div>
<script type="text/javascript">
var img = $('someImage');
// these are all equivalent ways of retrieving the link:
var link = img.up();
var link = img.up(0);
var link = img.up('a');
// similarly, there are several ways to retrieve the surrounding cell
var cell = img.up(1);
var cell = img.up('td');
// the foo class is used in two different places
var table = img.up('.foo');
var div = img.up('.foo', 1);
script>
body>
html>
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.
For example, if you have a generic JavaScript class that relies on
there being elements named in a particular way (by way of element IDs
or class names), you don't have to worry about the specific structure
of the elements in the DOM.
The down() method
The 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.
Just like 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.
Using 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 someElt.select('.foo')[0].
The important difference is that trying to reference an particular element when using select() is that a JavaScript error will occur if the select() call returns an empty array. This is not an issue when using down().
Listing 8 shows some examples of using down() to find an element's descendants.
Listing 8 Selecting an element's descendants using down() (listing-8.html)
<html>
<head>
<title>Selecting an element's descendants using down()title>
<script type="text/javascript" src="/js/prototype.js">script>
head>
<body>
<div id="main" class="foo">
<table class="foo">
<tr>
<td>
<a href="#"><img src="someImage.png" id="someImage" />a>
td>
<td>
Second cell
td>
tr>
table>
div>
<script type="text/javascript">
var div = $('main');
// there are several ways to find the table element
var table = div.down();
var table = div.down('table');
var table = div.down('.foo');
// you can specify an index to find a particular match
var secondCell = div.down('td', 1);
// complex selectors can be used
var image = div.down('table.foo a img#someImage');
script>
body>
html>
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 up() and down(). That is, you can use a numerical index or a CSS selector.
Listing 9 shows several examples of using next() and previous().
Listing 9 Using next() and previous() to find sibling elements (listing-9.html)
<html>
<head>
<title>Using next() and previous() to find sibling elementstitle>
<script type="text/javascript" src="/js/prototype.js">script>
head>
<body>
<div>
<ul>
<li id="first">First itemli>
<li id="second">Second itemli>
<li id="third">Third itemli>
<li id="fourth">Fourth itemli>
<li id="fifth">Fifth itemli>
ul>
div>
<script type="text/javascript">
var secondElement = $('first').next();
var secondElement = $('third').previous();
var thirdElement = $('third').previous().next();
// this call will return null since #fifth is the
// final child of the unordered list
var nullElement = $('fifth').next();
script>
body>
html>
Chaining traversal calls together
Because calls to up(), 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 elt.
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 elt.up().down(someSelector).
Note: Depending on your CSS selector, this may also
return the search target, not just its siblings. You may need to check
for this in your code if this is a problem.
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.
Creating New Elements and Inserting Them into the DOM
New in Prototype 1.6.0 is the ability to easily create new DOM elements
that will work across all browsers. An element is created by
instantiating the Element
class. The first argument to this class is the type of element to be
created, while the second argument is used to specify the element's
attributes.
Listing 10 shows how you would dynamically create a new hyperlink (that is, the equivalent of the using the HTML ). In this example, we call update() on the created element to set the link text.
After an element has been created, it must be inserted into the document. This is achieved by calling the insert() method on another element that already exists in the document.
<html>
<head>
<title>Creating a new element in the DOMtitle>
<script type="text/javascript" src="/js/prototype.js">script>
head>
<body>
<div id="main">
<div>Some itemdiv>
div>
<script type="text/javascript">
var attrs = {
href : 'http://www.example.com',
target : '_blank'
};
var link = new Element('a', attrs);
link.update('Visit this web site');
$('main').insert(link);
script>
body>
html>
Note: When you create the attributes for a new element, some attribute names need to be quoted. For example, using { class : 'MyClass' } will cause an error in some browsers. Instead, you should use { 'class' : 'MyClass'}.
If you were to manually create the HTML as generated by this JavaScript, it would like that in Listing 11.
<html>
<body>
<div id="main">
<div>Some itemdiv>
<a href="http://www.example.com" target="_blank">Visit this web sitea>a>
div>
body>
html>
When you call the insert() method with just the new
element as an argument, that new element then becomes the last child of
the target element. Alternatively, you can place the new element before
the target, after the target, or as the first child of the target. This
is done by slightly changing the argument to insert().
When we used $('main').insert(link), this was the equivalent of calling $('main').insert({ bottom : link }),
meaning it was inserted as the last child (as you can see in Listing
11, since it appears after the "Some Item" div). To make it appear
before the "Some item" div, you would use $('main').insert({ top : link }). This would result in HTML as in Listing 12.