Forum Moderators: open

Message Too Old, No Replies

getElementByClass

How to access and manipulate all objects of a certain class

         

BlobFisk

9:09 am on May 12, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



In the process of developing a web based application UI I had to devise a method that would allow us to manipulate objects of a certain class. I didn't want to be constrained by using the ID, as I wanted flexibility in the system. I didn't want to have to worry about what objects were on the which page for the script to know about.

Unfortunately, there is no getElementByClass, so I wrote one myself. For anyone interested here it is for you to use and abuse:


//Create an array
var allPageTags = new Array();

function doSomethingWithClasses(theClass) {
//Populate the array with all the page tags
var allPageTags=document.getElementsByTagName("*");
//Cycle through the tags using a for loop
for (i=0; i<allPageTags.length; i++) {
//Pick out the tags with our class name
if (allPageTags[i].className==theClass) {
//Manipulate this in whatever way you want
allPageTags[i].style.display='none';
}
}
}

The advatage for me was that I didn't need to worry about whether an ID was on a page or not. Scripts that manipulate elements usually work on the basis of the ID. If the ID is not part of the DOM (not on the page) the script will throw an error. Using a class name will manipulate every object which is of that class and as developers we don't need to worry about the presence of the ID or not.

I look forward to all comments and criticisms... But mainly the comments!

HTH

<edit>Typo Fix</edit>

[edited by: BlobFisk at 9:43 am (utc) on May 12, 2004]

Bernard Marx

9:26 am on May 12, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That's a good thing to have, BlobFisk.
Here a some ..er..comments.

1. The loop counter, i, should be a local var (a little more efficient).

2. Some versions of IE5 accept getElementsByTagName but return null when given the '*' argument. A quick check - and switch to the all collection if needed would make it disaster proof.

3. How about using it as a collecting function (getElementsByClass perhaps) that can be used generically, rather than putting your command inside.

4. Both getElementsByTagName and the all collection will work on any container, not just the document. You could have an optional second argument specifying the container, so giving more targetting possibilities.

BlobFisk

9:38 am on May 12, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks for your comments Bernard!

You're correct - this script is DOM1 only, and 5.5 on IE. There is a way of making it more compliant (as you pointed out).

You're right again, the next logical step is to make it a general function that you can feed in the name of the class that you want to manipulate, possibly by creating a new array that containes the objects of the class that you specify.

Bernard Marx

10:38 am on May 12, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Here's a more general one that picks up elements based on attribute value. Good if you are using custom attributes (and either have a DTD or don't care about validation).
It assumes that the container argument (if included) is an object reference - I don't bother giving it the facility to take an id string too.

*! convert ¦ to pipes, as usual


function getElementsByAttribute(attr,val,container)
{
container = container¦¦document
var all = container.all¦¦container.getElementsByTagName('*')
var arr = []
for(var k=0;k<all.length;k++)
if(all[k].getAttribute(attr) == val)
arr[arr.length] = all[k]
return arr
}

Stretching the point further, this one collects elements by condition:


function getElementsByCondition(condition,container)
{
container = container¦¦document
var all = container.all¦¦container.getElementsByTagName('*')
var arr = []
for(var k=0;k<all.length;k++)
{
var elm = all[k]
if(condition(elm,k))
arr[arr.length] = elm
}
return arr
}

The condition is in the form of a function (here the loop index is redundant, but it's in the collecting function in case you need it)


var helloElms = getElementsByCondition(function(el){return el.className.indexOf('hello')>-1})

The bonus feature of this is that you can perform an operation on an element at the same time. This gets us back to the full functionality of your original.


var hidden = getElementsByCondition(
function(el){if(el.className=='hiders'){el.style.display='none';return el}}
)

I'm not sure it's worth going this far though.

BlobFisk

4:24 pm on May 12, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Very nice - thanks for that!