The bleeding edge of web: querySelector() and querySelectorAll()
One thing coming up in the W3C selectors api spec are a couple of new methods for retrieving DOM elements called querySelector() and querySelectorAll() that take a css selector and return a node or list of nodes that match. They basically do the same thing as the css query features of JQuery or Dean Edward’s CSS Query libraries.
Both methods are available on any DOM element so you can use them to return children of an element you already have a reference to. They are also available on the document so you can query elements anywhere in the page.
The methods accept any css selector (really any selector!) that you could use to style your page. For a simple example, to retrieve a list of all button elements on the page you could call document.querySelectorAll(”input[type=button]“). It could also take a more complicated query like document.querySelectorAll(”#menu span a.category:visited”).
Here’s a simple example that gets the first div element on the page and any of the div’s child elements that are buttons:
-
function testQuerySelector(){
-
if(document.querySelector)
-
{
-
var divElement = document.querySelector("div");
-
divElement.style.backgroundColor = "yellow";
-
-
// Any CSS query – really
-
var buttons = divElement.querySelectorAll("input[type=button]");
-
for(var x=0; x<buttons.length; x++)
-
{
-
buttons[x].style.backgroundColor = "lime";
-
buttons[x].value = "querySelector sure is nifty!";
-
}
-
}
-
else
-
alert("This browser doesn't support document.querySelector");
-
}
Why’s it exciting?
It’ll make walking the DOM much easier.
Sometimes I feel like walking the DOM with the current APIs is like building something from the incredible machine. Imagine you wanted to get a reference to all the <a> tags in a menu that linked to an external website so you could attach a bit of script to them to do something before they opened. To get the links using getElementById() and getElementsByTagName() you’d need to do something like this:
-
var navigation = document.getElementById("navigation");
-
var links = navigation.getElementsByTagName("a");
-
-
var externalLinks = [];
-
for(var x=0; x<links.length; x++){
-
var url = links[x].getAttribute("href").substring(0, 7);
-
if(url == "http://")
-
externalLinks.push(links[x]);
-
}
-
alert(externalLinks.length + " external links");
The same thing using querySelectorAll() is a one liner:
-
var externalLinks =
-
document.querySelectorAll("#navigation a[href^='http://']");
-
alert(externalLinks.length + " external links");
Another good example for ASP.NET developers is being able to select elements by the end of their IDs for cases where you want to get access to an element that’s inside a naming container.
Here’s an example with a button in a repeater:
-
<asp :repeater ID="Repeater1" runat="server">
-
<itemtemplate>
-
<div class="item">
-
<asp :Label ID="Label" runat="server" Text='<%# Eval("column1") %>;'/>
-
</asp><asp :Button ID="ImportantLink" runat="server" Text='<%# Eval("column2") %>'/>
-
</asp></div>
-
</itemtemplate>
-
</asp>
You could iterate through the items inside the repeater like this:
-
var repeaterItems = document.querySelectorAll("div.item");
-
for(var x=0; x<repeateritems .length; x++)
-
{
-
var button =
-
repeaterItems[x].querySelector("input[id$='ImportantLink']");
-
button.style.backgroundColor = "yellow";
-
}
When’s it coming?
Safari – it already supports it. You can try it out in the Safari 4 preview.
IE – IE8 beta 1 supports this already! There’s a nice write up in the MSDN documentation. Fingers crossed it will make it to the IE8 release without any major problems.
Firefox – it’s supported in Firefox 3.1.
Opera – It’s been implemented already and can be tried out in the special Acid 3 build.
