22

Background and Setup

I'm trying to create a table from tabular data in javascript, but when I try inserting rows into a table element, it inserts in the opposite order from what I expect and the opposite order of what you get from using appendChild. (Here's a jsfiddle with a live demo of this).

Say I have some data like this:

var data = [
    {"a": 1, "b": 2, "c": 3},
    {"a": 4, "b": 5, "c": 6},
    {"a": 7, "b": 8, "c": 9}
], keys = ["a", "b", "c"];

If I try using the insertRow() and insertCell() methods for creating tables, iterating over the data and keys above. I get the reverse order of what I expect:

InsertRows pic

Generated by using the following code:

// insert a table into the DOM
var insertTable = insertDiv.appendChild(document.createElement("table")),
    thead = insertTable.createTHead(), // thead element
    thRow = thead.insertRow(), // trow element
    tbody = insertTable.createTBody(); // tbody element


thRow.insertCell().innerText = "#"; // add row header

// insert columns
for (var i = 0, l = keys.length; i < l; i ++) {
    var k = keys[i];
    thRow.insertCell().innerText = k;
}

// insert rows of data
for (var i = 0, l = data.length; i < l; i ++) {
    var rowData = data[i],
        row = tbody.insertRow();
    row.insertCell().innerText = i;
    for (var j = 0, l = keys.length; j < l; j ++) {
        var elem = rowData[keys[j]];
        row.insertCell().innerText = elem;
    }
}

Whereas, if I create a table using document.createElement and appendChild, I get the order I would expect:

AppendChild pic

Generated by:

// now do the same thing, but using appendChild
var byChildTable = document.createElement("table");
byChildTable.setAttribute("class", "table");
thead = byChildTable.appendChild(document.createElement("thead"));
thRow = thead.appendChild(document.createElement("tr"));

// create table header
thRow.appendChild(document.createElement("td")).innerText = "#";
for (var i = 0, l = keys.length; i < l; i ++) {
    var key = keys[i];
    thRow.appendChild(document.createElement("td")).innerText = key;
}

// insert table data by row
tbody = byChildTable.appendChild(document.createElement("tbody"));
for (var i = 0, l = data.length; i < l; i ++) {
    var rowData = data[i],
        row = tbody.appendChild(document.createElement("tr"));
    row.appendChild(document.createElement("td")).innerText = i;
    for (var j = 0, l = keys.length; j < l; j ++) {
        var elem = rowData[keys[j]];
        row.appendChild(document.createElement("td")).innerText = elem;
    }
}

Question

How do I control the order it puts the elements in the DOM? Is there any way to change this? I guess otherwise I could iterate in reverse order, but even that way, you still can't insert with table.insertRow(). It's just a bummer because the insertRow() and insertCell() methods seem much clearer than table.appendChild(document.createElement("tr")) etc.

Jeff Tratner
  • 16,270
  • 4
  • 47
  • 67
  • 1
    `insertRow()` Takes an index as an argument so you can choose where to place the newly inserted row. https://developer.mozilla.org/en-US/docs/DOM/table.insertRow – Sukima Apr 07 '13 at 19:17
  • wow - I feel a bit silly about that now - I guess I just missed that on MDN. Thanks all! – Jeff Tratner Apr 07 '13 at 19:20
  • FYI, some of the methods you're using don't work in Firefox. I think you'll need `.appendChild()` instead of `.createTBody()` and `.createTHead()`. Also, Firefox will throw an error if you don't include the index in the `insertCell()` and `.insertRow()`. –  Apr 07 '13 at 19:23
  • @amnotiam thanks, good to know. Apparently the `appendChild` method is faster too. – Jeff Tratner Apr 07 '13 at 19:28
  • 1
    @JeffTratner: You're welcome. Also, Firefox doesn't honor the non-standard `.innerText`. The standard property is `.textContent`. IE8 and lower need `.innerText`, so if you support those browsers, I would make a variable like this at the top of your application: `var text = ("textContent" in document) ? "textContent" : "innerText";`, and then use it to get and set text. `row.insertCell(-1)[text] = k;` Here's a full working version: http://jsfiddle.net/ZfqRu/ –  Apr 07 '13 at 19:31
  • @amnotiam thanks for the tip--that's really helpful to know for the future! – Jeff Tratner Apr 07 '13 at 19:37

4 Answers4

48

The .insertRow and .insertCell methods take an index. In absence of the index, the default value is -1 in most browsers, however some browsers may use 0 or may throw an error, so it's best to provide this explicitly.

To to an append instead, just provide -1, and an append will be done

var row = table.insertRow(-1);
var cell = row.insertCell(-1);

https://developer.mozilla.org/en-US/docs/DOM/table.insertRow

4

You can do this:

var table = document.getElementById('myTableId');
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
Codingpan
  • 318
  • 2
  • 6
2

You have to specify an index in insertCell() like insertCell(inde) in order to work as you expect.

As it is said in www.w3schools.com/jsref

If this parameter is omitted, insertCell() inserts the new cell at the last position in IE and at the first position in Chrome and Safari.

This parameter is required in Firefox and Opera, but optional in Internet Explorer, Chrome and Safari.

An index is required also in inserRow() for the same reason.

vortex7
  • 351
  • 3
  • 7
  • @vortex7: FYI, to highlight documentation, use the *blockquote* formatting instead of the code formatting. –  Apr 07 '13 at 19:24
2

You can do this,

var table = document.getElementById("yourTable");
var row = table.insertRow(-1);

var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);