Griffin_0
Griffin_0

Reputation: 47

getElementsByTagName("td") doesn't return all td children for a selected row

I've created a javascript function that invert rows and columns of a table. Here is the code :

function rotate(){
            var table = document.getElementById("table");
            var newtable = document.createElement("table");

            var tablebody = table.getElementsByTagName("tbody")[0];
            var newtablebody = document.createElement("tbody");
            newtable.appendChild(newtablebody);

            var rows = tablebody.getElementsByTagName("tr");

            var heads = tablebody.getElementsByTagName("th");

            var i;
            for(i = 0; i < rows.length; i++)
            {
                var cells = rows[i].getElementsByTagName("td");
                var j;
                for(j = 0; j < heads.length; j++)
                {
                    if(newtablebody.getElementsByTagName("tr")[j] == undefined)
                    {
                        var newrow = document.createElement("tr");
                        newtablebody.appendChild(newrow);
                    }
                    if(cells[j] == undefined)
                    {
                        var newcell = document.createElement("td");
                        newtablebody.getElementsByTagName("tr")[j].appendChild(newcell);
                    }
                    else
                    {
                        var newcell = cells[j];
                        var nbspan = cells[j].getAttribute("colspan");
                        newcell.setAttribute("rowspan", nbspan);
                        newcell.setAttribute("colspan", 1);
                        newtablebody.getElementsByTagName("tr")[j].appendChild(newcell);
                    }
                }
            }
            table.innerHTML = newtable.innerHTML;
        };

The problem is that when I try to get all children with tag name "td" for the current row, I get a lot of undefined cells, whereas I can see from the console log that these cells exist and contain data (I display innerHTML in the log).

I'm really lost, so any help would be appreciated. Thanks!

Upvotes: 3

Views: 2493

Answers (1)

Pointy
Pointy

Reputation: 413737

When you append an existing cell to the new table row, you implicitly remove it from the old table row; a cell can only be in one place in the DOM at a time. The node list that is returned by getElementsByTagName() is live, which means that removing that cell from the table row also immediately removes it from the cells array. That means that the cell that was at cells[j] is suddenly gone, and cells[j] thus becomes the next cell in the (old) table row. Your loop, however, still increments j, so you skip a cell whenever that happens.

One simple way to get past the problem is to copy the node list into an array before you start the loop:

   var cells = rows[i].getElementsByTagName("td");
   cells = [].map.call(cells, Object); 

Now you've got a plain array, and elements won't magically disappear from it.

Upvotes: 3

Related Questions