views:

70

answers:

1

I'm getting the weirdest issues with Javascript in Firefox today.

I'm trying to manipulate some table rows, but .getElementsByTagName("tr"); is pulling back junk.

dynamicTable.tableBody = dynamicTable.getElementsByTagName("tbody")[0];
var tableRows = dynamicTable.tableBody.getElementsByTagName("TR");
var actualTableRows = new Array();
for(var i in tableRows) {
    var row = tableRows[i];
    alert(row.tagName);
    if(row.tagName == "TR"){
       actualTableRows.push(row);
    }
}
dynamicTable.bodyRows = actualTableRows;

The puzzling part of course is my temporary hack to fix the error. For some reason .getElementsByTagName("tr") is pulling back some functions also.

Incidently the alert above goes something like this TR TR TR TR undefined undefined undefined.

The code I wanted was something like this

dynamicTable.bodyRows = dynamicTable.tableBody.getElementsByTagName("tr");

But then bodyrows does not contain just tr elements it has the aforementioned junk in it.

Any thoughts?

EDIT: If I just use the second block of code, I get a list 24 elements long on a table that has 21 table rows (tr elements) . The first block of code is just a hack that fixes the problem.

if I change the alert to alert(row) I get

[object HTMLTableRowElement] ...

function item() { [native code] }

21

function namedItem() { [native code] }

+5  A: 

The for-in statement is enumerating also the item and namedItem methods present on the HTMLCollection that getElementsByTagName returns.

To iterate over array-like elements like DOM Collections, a simple sequential loop is always recommend, the for...in statement is meant to be used to enumerate object properties.

dynamicTable.tableBody = dynamicTable.getElementsByTagName("tbody")[0];
var tableRows = dynamicTable.tableBody.getElementsByTagName("TR");
var actualTableRows = new Array();
for(var i = 0, n = tableRows.length; i < n; i++) { // <---- simple for loop
    var row = tableRows[i];
    alert(row.tagName);
    if(row.tagName == "TR"){
       actualTableRows.push(row);
    }
}
dynamicTable.bodyRows = actualTableRows;

You shouldn't use for..in with array-like objects because:

  • The order of iteration is not guaranteed, the array indexes may not visited in the numeric order.
  • Inherited properties are also enumerated (This can be another source of problems).

Recommended article:

CMS
+1 exactly 5 seconds faster.
MvanGeest
The enumeration is not the problem the problem exists before the enumeration happens
Sheldon Ross
@Sheldon, `for-in` enumerates also over the `item` and `namedItem` methods of [HTMLCollections](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75708506)
CMS
Ah, that was the problem in another unposted block of code, I enumerated over it then and it pulled back all the properties of tableRows not just the actual entries. I assumed the .getElementsByTagName was pulling back too many things.
Sheldon Ross