6

Using Javascript, I am trying to add a new table row into the the middle of a table, where the new table row is a copy of one of the pre-existing rows.

There are a lot of questions similar to this on stackoverflow, but none seemed to help me solve this problem.

function AddRow()
{
    var mainTable = document.getElementById('mainTable');

    mainTable.insertBefore(
        mainTable.rows[0].cloneNode(true),
        mainTable.rows.childNodes[2]);
}

I know the problem exists in the last variable passed to insertBefore(), as if I leave this blank the code performs correctly and inserts the cloned first row at the end of the table (if no 2nd parameter is present, it acts like appendRow().

I get the error "Cannot read property 2 of undefined", which I guess means it's not recognising mainTable.rows.childNodes as a valid object to be indexing.

I have also tried the following method, and got the more elusive error "NotFoundError: DOM Exception 8" when testing it

function AddRow()
{
    var mainTable = document.getElementById('mainTable');

    mainTable.insertBefore(
        mainTable.rows[0].cloneNode(true),
        mainTable.rows[2]);
}

EDIT: Note that mainTable.appendChild(mainTable.rows[0].cloneNode(true)) works fine! Problem is I don't want to add it the the end of the table.

3
  • 1
    The table may not be the parent of the row(tbody maybe) Commented Jun 8, 2013 at 21:54
  • If it wasn't, what implication does that have on my code? I can't see why it would matter if it was child element or say, and grand-child element. Commented Jun 8, 2013 at 23:04
  • insertBefore assumes a direct child for the reference value. Commented Jun 8, 2013 at 23:19

2 Answers 2

4

The confusion should be due to the fact that you are using the HTMLTableElement interface (by using the rows property)--which abstracts table access and thus can find the rows even though there is an intervening implicit tbody element--along with the regular DOM method (insertBefore) which expects the reference node to be a direct child of the node on which the method is invoked.

As pointed out in another answer, you can use the insertRow method for consistent table abstraction via the HTMLTableElement interface.

However, if you want to know how to do it along with the vanilla DOM way, you can do so by being aware of the assumed tbody:

var mainTable = document.getElementById('myTable');
var tbody = mainTable.children[0]; // or to use HTMLTableElement, mainTable.tBodies[0]

// Mixing HTMLTableElement with vanilla DOM
tbody.insertBefore(mainTable.rows[0].cloneNode(true), mainTable.rows[2]);

// or pure vanilla DOM:
// tbody.insertBefore(tbody.children[0].cloneNode(true), tbody.children[2]);
<table id="myTable">
  <tr>
    <td>1</td>
    <td>2</td>
  </tr>
  <tr>
    <td>3</td>
    <td>4</td>
  </tr>
  <tr>
    <td>5</td>
    <td>6</td>
  </tr>
</table>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this worked perfectly! That hidden tBody is what got me. One day I will do it more cleanly with consistent table abstraction via insertRow().
4

You can calculate the table rows and use the table native methods to dinamically instert rows:

function appendRow(){
var table = document.getElementById('myTable');
var middleRow = table.insertRow( Math.floor( table.rows.length / 2 ) );
var cell1 = middleRow.insertCell(0);
var textnode1=document.createTextNode('dom insterted');
cell1.appendChild( textnode1 );
}

function cloneRow(){
var table = document.getElementById('myTable');
var row = document.getElementById("rowToClone"); // find row to clone
var clonedRow = row.cloneNode(true); 
clonedRow.id = "newID"; // change id or other attributes/contents
//table.appendChild(clonedRow); // add new row to end of table
var middleRow = table.insertRow( Math.floor( table.rows.length / 2 ) );
var cell1 = middleRow.insertCell(0);    
 cell1.appendChild( clonedRow );   

}

check out this working demo

2 Comments

Your code inserts a new blank row into the table (and then you fill it with content using createTextNode()), but how would I then copy the HTML content from a pre-existing row into this new, blank row? That's why I was trying to use the insertBefore() method, as it took an existing row object as input.
Thanks for your help. I accepted @BrettZamir 's answer however, as he provided the solution which best fitted the question. Also, your answer kind of copies "cells" rather than rows. For example, if you add another column into the table, your clone Javascript concatenates the two columns into the single cell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.