I’ve been waiting for this one for a while – and it was just committed to the Mozilla trunk yesterday:
Firefox 3 is going to have support for getElementsByClassName.
Robert Sayre just merged in his changes yesterday, taking this feature live.
If you’re curious as to why this feature is being included (or where the reasoning for it originated from) – it’s because it’s part of the Web Applications 1.0 (HTML 5) specification. The implementation that’s in Firefox is slightly different from what’s presented in the specification; however, you can expect that the specification will probably be updated to reflect that changes that’ve been made.
getElementsByClassName has long been a mainstay of web developers everywhere – and by making it official (both in specification and in implementation), web applications are going to see a huge jump in speed.
I’ve pulled together some simple examples of what you can do with this new element selector.
Get all elements that have a class of ‘test’
document.getElementsByClassName('test')
Get all elements that have a class of ‘red’ and ‘test’
document.getElementsByClassName('red test')
Get all elements that have a class of ‘test’, inside of an element that has the ID of ‘main’
document.getElementById('main').getElementsByClassName('test')
And if we go ahead and add in JavaScript 1.6’s Array extras, we can do some really-cool matches.
Find all div elements that have a class of ‘test’
Array.filter( document.getElementsByClassName('test'), function(elem){ return elem.nodeName == 'DIV'; });
Find all elements that have a class of ‘test’ (as do their parent element)
var test = document.getElementsByClassName('test'); Array.filter( test, function(elem){ return Array.indexOf( test, elem.parentNode ) > -1; });
Some basic code can be found in the test cases for this feature. You’ll need to have a nightly version of Firefox in order to run the code contained within it. I really can’t wait until this is live.
Update: This post has been submitted to Digg.
Update: This function is now documented on the MDC Wiki.
Sebastian Redl (February 2, 2007 at 2:02 pm)
> Find all elements that have a class of ‘test’ (as do their parent element)
That’s a linear search for every entry, O(n²). Sounds slow to me. Better to access elem.parentNode.className and do a standard class test.
I wonder why no one thought to implement a property “classes” for nodes that contains an array of the individual class names. Live, of course. It would be so much simpler than the current string manipulations.
Shawn Wilsher (February 2, 2007 at 2:09 pm)
What differs from the spec?
Do you know off hand if Opera already implemented this, and as a result of the changes, what they might do (if they already implemented it)?
John Resig (February 2, 2007 at 2:17 pm)
@Sebastian – I agree, a classes property would be fantastic.
elem.classes.push(“test”)
elem.classes.indexOf(“test”) > -1
And a best-case scenario for removing a class would be (Since neither the current solution nor our imaginary solution would solve this):
elem.classes.remove( “test” )
Maybe it’s not too late to explore something like this?
John Resig (February 2, 2007 at 2:23 pm)
@Shawn – Looking through the spec and the implementation, it appears as if this case is not handled?
Which is fine by me – handling the string case seems to be an ideal solution anyway.
Although, maybe this wouldn’t be a bad idea?
document.getElementsByClassName(“foo”, “bar”)
And, no, Opera does not seem to have support for getElementsByClassName.
One final item: I wonder why there isn’t a way to test if something simply has any class?
document.getElementsByClassName(“*”)
Robert Sayre (February 2, 2007 at 11:26 pm)
differences from the spec have to do with accepting an array argument (and the examples contradict the spec text at this time). The final implementation will conform with whatever the spec says.
Sebastian Redl (February 3, 2007 at 1:33 pm)
> Maybe it’s not too late to explore something like this?
Oh yes, let’s.
http://stud3.tuwien.ac.at/~e0226430/stuff/clsarray.html
The script in there is highly dependent on property getters and setters – __defineGetter__ and __defineSetter__, that is – which means it probably works only in Gecko, but it’s still very interesting.
zimbatm (February 5, 2007 at 4:09 am)
Great but why not directly include XPath and CSS selector methods ?
DigDug (February 5, 2007 at 10:31 am)
I was thinking the same thing. This is nice and all, but doesn’t XPath provide exactly the same thing? Why not just encapsulate XPath searching a little better so that you could write:
document.getElementsByXPath();
Then you could, in one line of script, do this and about a million other things. This just seems like a waste of space to me. What’s next, getElementsByFont?
Glen Lipka (February 7, 2007 at 12:55 pm)
Why not just bundle jQuery with the browser? I say this only half-joking. It seems easier to do it in jQuery than the examples above, plus re:DigDug, it has xPath in it too.
Sebastian Redl (February 9, 2007 at 8:17 am)
Because getElementsByClassName is in a (working draft) specification, and this specification is quite a bit older than jQuery.
Besides, jQuery, and all other JS frameworks and libraries too (for who’s to say that jQuery is so superior that it should be the choice for the bundled library), is evolving far too fast to be bundled with anything.
Oh, and there’s the speed issue. I’m sure jQuery can be made to be a bit faster with this new function. (Although a bundled jQuery could access the native CSS matcher and blow everything else away.)
Tarwin Stroh-Spijer (February 15, 2007 at 8:13 am)
This will be a great boost to any JS toolkit that uses getElementsByClassName(). Yay for that. It does seem strange to not also include at least a getElementByCSS() as I’m sure the function is already written into the browser, at least in the CSS parser module.
I’m sure that ‘dem smart folks is already working on it, things just move slowly in the large implementation arenas – it’s going to be YEARS before IE gets this I’m sure, at least this doesn’t stop people from using it as they always have!
Mislav (March 3, 2007 at 12:40 pm)
Prototype framework already has element.classNames property that acts as Enumerable and provides add() and remove() methods.
See http://prototypejs.org/api/element/classNames and http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/src/dom.js?rev=6283#L738 (the implementation)
Michael Kaply (March 8, 2007 at 9:27 am)
This is great, but it’s not enough. We also need “get elements by attribute name/value”
Daniel Aquino (March 28, 2007 at 4:20 pm)
Michael Kaply,
Thats exactly the way I felt a while ago… I keep wondering why everyone just wants getElementsByClassName and why not something more generic allowing you to select based on any criteria…
Thats why I put together this function to do just that, getElementsByAttributes:
http://chino.homelinux.org/projects/getElementsByAttributes.html
free music for ipod (September 14, 2007 at 7:41 pm)
Hi boys!94e6052e6de4f6c99890ca7e44e5438e
Easyrules (October 4, 2007 at 6:29 am)
Here it is good blog