I think an oft overlooked feature of the $$ utility method and other similar methods - select(), up(), down(), etc. - is their (almost) full css3 selector support. These advanced selectors have been available since prototype 1.5.1 (and I believe similar functionality is found in jQuery), but I often see code that doesn’t take advantage of them. Take the following markup:
<div class="example">
<p class="inner" title="Block 1">Block 1</p>
</div>
<div class="example">
Block 2</p>
</div>
<div class="example">
<p class="inner" title="Block 3">Block 3</p>
</div>
<div class="example" id="example-4">
<p class="inner" title="Block 4">Block 4</p>
</div>
When selecting portions of the preceeding code, one might be tempted to use the $$ method combined with a loop.
// shade the background of even numbered divs
$$('.example').each(function(div,i){
if(i%2==0) div.setStyle({background: '#ccc'});
});
A more concise, and efficient, way to achieve this effect would be to use css3 selectors.
$$('.example:nth-child(even)').invoke(
'setStyle',{background: '#ccc'}
);
The :nth-child pseudo-class is part of the css3 specification. The class takes one argument. You could use ‘even’ or ‘odd’ as we did above or get a bit more complicated by using the format an[ + b]. Sounds a bit complicated, but once you see a few examples it becomes clearer.
// another way to select all the even divs
$$('.example:nth-child(2n)');
// select every third div
$$('.example:nth-child(3n)');
// get all the even divs starting with
//div number three (only the fourth div)
$$('.example:nth-child(2n+3)');
// simpler syntax to select only the fourth div
$$('.example:nth-child(4)');
Other useful filters include :last-of-type, :first-of-type and :not(). Their functions should be self-explanatory, but lets look at the syntax.
// pick the last div
$$('.example:last-of-type');
// pick the first div
$$('.example:first-of-type');
// pick anything that doesn't have an
// id of 'example-4'
$$('.example:not(#example-4)');
One final selector I want to discuss is the attribute selector. While its simplest incarnation may be familiar to many developers its more powerful than many realize. Allowing selections based on a tag having a specific attribute, having an attribute with a specific value, or even based on some simple regex-like substring searching.
// simplest incarnation any paragraph
// that has a title attribute
$$('p[title]');
// title attribute with a specific value
$$('p[title="Block 1"]');
// title attribute with a value
// that BEGINS with 'Block'
// selects every p tag in our example
$$('p[title^="Block"]');
// title attribute with a value that
// contains the letters 'ock' somewhere
// in the string. Again would select
// all of our p tags
$$('p[title*="ock"]');
// this selector is very useful in forms
// especially with the input tag to only
// select certain types of inputs
$$('input[type="hidden"]');
While powerful on their own, these selectors become amazingly flexible when combined. There really should be very few instances where you find yourself in a situation where you can’t find the correct DOM node.
// select all the even divs that don't
// have an id of example-4
$$('.example:nth-child(even):not(#example-4)');
// select all the even divs that are not
// the last sibling div and don't have a
// title attribute
$$('div:nth-child(even):not(:last-of-type):not(div[title])');
There are several more selectors you should familiarize yourself with, all of which are explained in the specification. If you find yourself having problems getting the syntax exactly right, I highly recommend the Selectoracle. A utility that will explain css selectors in plain english.
One Last Thing
don’t forget about the select() method. By using this method you can limit the amount of the DOM your script has to search over to match your selectors. Instead of searching the entire your document, you can specify the id of an element to use as the bounds of the selector
// find the even number divs that are inside
// the #myId element
$('myId').select('div:nth-child(even'));
That’s all folks, happy selecting. If you have any particularly useful selectors, show em off in the comments.