...

View Full Version : Select similar elements with DOM



guvenck
08-23-2007, 03:14 PM
Hi,

I have similar blocks on the webpage. They are actually tables with same class.



<table class="default" width="100%" cellspacing="0" cellpadding="0">
<tr><th>Block Title</th></tr>
<tr><td valign="top">Block content</td></tr>
</table>

<br style="line-height:10px">

<table class="default" width="100%" cellspacing="0" cellpadding="0">
<tr><th>Another Block Title</th></tr>
<tr><td valign="top">Another Block content</td></tr>
</table>

<br style="line-height:10px">


I would like to select and access these elements by DOM. How can I do this? I can give them an ID but as they are generated, they all will have the same ID and I guess this is not possible.

Arbitrator
08-23-2007, 03:31 PM
I would like to select and access these elements by DOM. How can I do this?
d = document;
var tables = d.getElementsByTagName("table");

If you want to narrow down things by class attribute, you could loop through the tables.


for (var i = 0; i < tables.length; i++) {
if (tables[i].hasAttribute("class") && tables[i].getAttribute("class").match(/(^| )default( |$)/)) {
// do something
}
}

Of course, Internet Explorer doesn’t support references to class attributes properly, so the less intuitive DOM HTML must be used.


for (var i = 0; i < tables.length; i++) {
if (tables[i].className && tables[i].className.match(/(^| )default( |$)/)) {
// do something
}
}

coothead
08-23-2007, 04:02 PM
Hi there guvenck,

you may find this rather unsophisticated but nevertheless mildly amusing...

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<script type="text/javascript">
window.onload=function() {
getTable();
}
function getTable(){

ta=document.getElementsByTagName('table');

for(c=0;c<ta.length;c++){
if(ta[c].className=='default') {

th=ta[c].getElementsByTagName('th');
td=ta[c].getElementsByTagName('td');

for(k=0;k<th.length;k++){
alert('table number '+(c+1)+'\nth number '+(k+1)+
' has this content...\n\n'+th[k].firstChild.nodeValue);
}
for(l=0;l<td.length;l++){
alert('table number '+(c+1)+'\ntd number '+(l+1)+
' has this content...\n\n'+td[l].firstChild.nodeValue);
}
}
}
td[0].firstChild.nodeValue='Lorem ipsum has now been removed';
}
</script>

</head>
<body>

<table class="default" width="100%" cellspacing="0" cellpadding="0">
<tr><th>Block Title</th></tr>
<tr><td valign="top">Block content</td></tr>
</table>

<br style="line-height:10px">

<table class="default" width="100%" cellspacing="0" cellpadding="0">
<tr><th>Another Block Title</th></tr>
<tr><td valign="top">Another Block content</td></tr>
</table>

<br style="line-height:10px">
<table class="default" width="100%" cellspacing="0" cellpadding="0">
<tr><th>Lorem Ipsum</th></tr>
<tr><td valign="top">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin massa. Nam vehicula.
Morbi velit nisi, mollis id, ultrices luctus, adipiscing sit amet, lectus. Nunc rhoncus
nisl ac enim. Maecenas vestibulum dolor ut velit.</td></tr>
</table>

</body>
</html>
coothead

guvenck
08-23-2007, 07:09 PM
Thanks to both posts, they are VERY helpful. I think I'll be able to solve my problem this way, thank you very much.

@Arbitrator:

Why did you use match() and regular expression rather than className="default"?

Arbitrator
08-23-2007, 07:32 PM
@Arbitrator:

Why did you use match() and regular expression rather than className="default"?In cases where you have multiple classes assigned to an element, "default" will not match something like class="class1 default class3 class4". If you know for certain that the elements will not have multiple class names, then you can scrap the regular expressions; I don’t know how the code will be used, so I wrote the code to be robust just to be safe.

liorean
08-23-2007, 07:39 PM
@Arbitrator:

Why did you use match() and regular expression rather than className="default"?

First of all, that'd be className==="default". (Or ==, but I prefer the version that doesn't autocast.)

Second, he's doing it that way since className is a space separated list or classes, and you may want to use more than one class on the same element. Using regex that way he makes sure the code doesn't break if the element has more than one class.


Personally I'd use
var
i=0,
elm;
while(elm=tables.item(i++)){
if(/\bdefault\b/.test(elm.className)){
// do something
}
} instead of
for (var i = 0; i < tables.length; i++) {
if (tables[i].className && tables[i].className.match(/(^| )default( |$)/)) {
// do something
}
} for a number of reasons:
- Code is smaller, simpler, and the syntax stands out more.
- It caches the element instead of looking it up multiple times.
- The regex works slightly differently but should do the work unless you have rather uncommon characters in the classes used for your code, and it's easier to see what it does at a glance.
- The regex just performs a boolean test instead of a match (the results of which were thrown away directly anyway), so it doesn't have to spend time and footprint on creating the array.

rwedge
08-24-2007, 12:37 AM
Personally I'd use
var
i=0,
elm;
while(elm=tables.item(i++)){
if(/\bdefault\b/.test(elm.className)){
// do something
}
}

Since i will increment before the conditional, the first table will be missed and the last will not exist
var
i=0,
elm;
while(elm=tables.item(i)){
if(/\bdefault\b/.test(elm.className)){
// do something
}
i++;
}

liorean
08-24-2007, 11:20 AM
Since i will increment before the conditional, the first table will be missed and the last will not existActually, no, that won't happen. The code I posted uses post-increment. That means that first time through the loop, elm will contain tables.item(0), and i will be incremented to 1.

I should have mentioned though, you use elm instead of tables[i] inside the actual loop. That means you never have to care about what the the value of i is in the loop body at all.

Also as you can see it uses tables.item in the condition of the loop and doesn't compare to the length of that collection at all. The reason that works is that the condition will return null when you try to access an element that doesn't exist in the collection. In other words, the last table looped over will be the last element in the collection.

Bill Posters
08-24-2007, 11:41 AM
Fwiw…

function getElementsByClassName(cName,trgtTagName,trgtNode) {

if (!document.getElementsByTagName) return true;

var cNameRegEx = new RegExp('(^|\\s)' + cName + '(\\s|$)');

var tName = trgtTagName || '*';
var tNode = trgtNode || document;

var trgtEls = [];
var trgt = 0;

var els = tNode.getElementsByTagName(tName);
for (var i = 0, tEl; tEl = els[i]; i++) {
if (tEl.className && tEl.className.match(cNameRegEx)) {
trgtEls[trgt] = tEl;
trgt++;
}
}

return trgtEls;

}

e.g.

var trgtTables = getElementsByClassName('default','table');

rwedge
08-24-2007, 11:49 AM
I should have mentioned though, you use elm instead of tables[i] inside the actual loop. That means you never have to care about what the the value of i is in the loop body at all. I was considering the usage of tables[i], thanks for clarifying.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum