If you can avoid using the elements, and just put a string into an innerHTML
you'll get the best performance. Here are some different ways to create a table.
Functional Code demo
We can create some functions to generate our HTML. This code will be very fast (but could be faster). We'll assume this data for all of these examples.
var heading = ['Name', 'Points'];
var data = [
["Joe", 50],
["Jack", 80],
["Doug <b>'the hammer'</b> Jones", 76]
];
We can then generate our table like so,
document.body.innerHTML = table(heading, data);
function wrapTag(tag, html) {
return "<" + tag + ">" + html + "</" + tag + ">";
}
function table(head, body) {
return wrapTag("table", thead(head)
+ tbody(body));
}
function thead(head) {
var _th = head.map(wrapTag.bind(null, "th"));
var _tr = wrapTag("tr", _th.join("\n"));
return wrapTag("thead", _tr);
}
function tbody(body) {
return body.map(tr).join("\n");
}
function tr(row) {
var _td = row.map(wrapTag.bind(null, "td"));
return wrapTag("tr", _td.join("\n"));
}
KnockoutJS demo
In Knockout we can give it an object, and have it map directly to our HTML. With the heading
and data
variables defined above, we map this like so.
ko.applyBindings({heading: heading, data: data});
Our HTML makes use of the foreach
binding, which iterates over an array. $data
refers to the current array item.
<table>
<thead>
<tr data-bind="foreach: heading">
<th data-bind="text: $data"></th>
</tr>
</thead>
<tbody data-bind="foreach: data">
<tr data-bind="foreach: $data">
<td data-bind="html: $data"></td>
</tr>
</tbody>
</table>
AngularJS demo
Using the same data from above, we can create an AngularJS controller.
function MyTableCtrl($scope) {
$scope.heading = heading;
$scope.data = data;
}
Our HTML is similar to KnockoutJS. One difference is the looping syntax, which lets us name our elements, e.g., row in data
, instead of referring to elements as $data
.
<table ng-controller="MyTableCtrl">
<thead>
<tr>
<th ng-repeat="head in heading">{{head}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in data">
<td ng-repeat="content in row" ng-bind-html-unsafe="content"></td>
</tr>
</tbody>
</table>
documentFragment demo
credit to @Ian
This is faster than regular DOM manipulation, and provides a nicer syntax than combining strings.
newTable = createTable(heading, data);
document.body.appendChild(newTable);
function createTable(h, c) {
var frag, table, head, body;
frag = document.createDocumentFragment();
table = document.createElement("table");
head = createHeader(h);
body = createContent(c);
table.appendChild(head);
table.appendChild(body);
frag.appendChild(table);
return frag.cloneNode(true);
}
function createHeader(data) {
var thead, rowEl, col, colEl, text, i, j;
thead = document.createElement("thead")
rowEl = document.createElement("tr");
for (i = 0, j = data.length; i < j; i++) {
col = data[i];
colEl = document.createElement("td");
text = document.createTextNode(col);
colEl.appendChild(text);
rowEl.appendChild(colEl);
}
thead.appendChild(rowEl);
return thead;
}
function createContent(data) {
var content, row, rowEl, col, colEl, text, i, j, k, l;
content = document.createElement("tbody");
for (i = 0, j = data.length; i < j; i++) {
row = data[i];
rowEl = document.createElement("tr");
for (k = 0, l = row.length; k < l; k++) {
col = row[k];
colEl = document.createElement("td");
text = document.createTextNode(col);
colEl.appendChild(text);
rowEl.appendChild(colEl);
}
content.appendChild(rowEl);
}
return content;
}