What\'s the best way to get an array of all elements in an html document with a specific CSS class using javascript?
No javascript frameworks like jQuery allowed her
The below answer is now pushing four years old, so it's worth noting that native browser support for getElementsByClassName() has gotten a lot better. But if you must support older browsers, then...
Use one that's already been written. Most major JS libraries include one in some form or another, but if you aren't using one of them then i can recommend Robert Nyman's excellent implementation:
http://code.google.com/p/getelementsbyclassname/
http://www.robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/
There are just too many ways to make this (conceptually-simple) routine slow and buggy to justify writing your own implementation at this point.
Use jquery, it can't be more convenient.
$(".theclass") or $(".theclass"),makeArray() if you want a native JS array
@shog9, @user28742, @bdukes - I'm doing some custom development in SharePoint for a modular thing (custom field definition) I hope can be re-used across many sites.
Since I can't know ahead of time if any given SharePoint site will have jQuery or any other library available to it --- I still need to write things in raw javascript so I can have a degree of confidence that the functionality I'm trying to achieve will stand on it's own.
Thanks Dmitri for your particular implementation. Short enough for my purposes.
In other recent efforts, I had to modify a e-commerce store (of my client's choosing) and some of my attempts to get jQuery rigged into it actually conflicted with whatever custom libraries they had previously rigged. I could have been persistent, and banged out a way to implement jQuery into their proprietary system.. or.. even more quickly.. just write some good ol' fashioned javascript.
Libaries ARE NOT ALWAYS THE BEST ANSWER!!!!!!!!!!!!!!!!
(and I love jQuery more than my grandmother)
If you want to do something for all the element with same id in a document. Although simple but sometime mind dont give green signals
var x = document.getElementById(elementid);
while(x){
document.removechild(x);
x = document.getElementById(elementid);
}
Just to do some follow up, I based my code on the the Robert Nyman implementation posted by Shog9, but departed a little from his exact version, for three reasons:
document.getElementById()
or document.getElementsByTagName()
.Note that I still relied mostly on his code. His javascript skills are obviously far beyond my own. I did try to factor out some redundant variables, but that's about it.
With that in mind, here is what I ended up with (seems to work in IE6, IE7, Firefox 3, and Chrome see new note at the end):
if (!document.getElementsByClassName)
document.getElementsByClassName = function (className)
{
var classes = className.split(" ");
var classesToCheck = "";
var returnElements = [];
var match, node, elements;
if (document.evaluate)
{
var xhtmlNamespace = "http://www.w3.org/1999/xhtml";
var namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace:null;
for(var j=0, jl=classes.length; j<jl;j+=1)
classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
try
{
elements = document.evaluate(".//*" + classesToCheck, document, namespaceResolver, 0, null);
}
catch(e)
{
elements = document.evaluate(".//*" + classesToCheck, document, null, 0, null);
}
while ((match = elements.iterateNext()))
returnElements.push(match);
}
else
{
classesToCheck = [];
elements = (document.all) ? document.all : document.getElementsByTagName("*");
for (var k=0, kl=classes.length; k<kl; k+=1)
classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
for (var l=0, ll=elements.length; l<ll;l+=1)
{
node = elements[l];
match = false;
for (var m=0, ml=classesToCheck.length; m<ml; m+=1)
{
match = classesToCheck[m].test(node.className);
if (!match) break;
}
if (match) returnElements.push(node);
}
}
return returnElements;
}
Update:
One new note on this. I've since re-read the notes on the original implementation, and I understand now that my code could fall down in the case where the existing browser has it's own implementation, because the default implementations return a nodelist where this returns an array. This includes the more recent firefox and safari, and opera browsers. Most of the time that won't matter, but in some situations it could. That explains item #2 from list above.
What that means is that while my code technically does work everywhere, it could result in subtly different (read: hard to debug) behavior in different places, and that's not good. I should fix this to either also return a nodelist or override the supplied method to return an array (which is what the original did). Probably the former would be simpler, but that latter would be better.
However, it's working at the moment in the local intranet environment (pretty much all IE), so for the time being I'll leave the fix as an exercise for the reader.
Keep in mind that atleast FF3 already has a native implementation of getElementsByClassName afaik.
If you're going to implement your own solution, maybe you should try to find a xpath-solution since all modern browser have native support for xpath.