I have a JSON array coming in from the server with an array of 200 objects each containing another 10 objects that I want to display in a table format. At first I was creati
This is definitely do-able. I don't think string concatenation is the way to go. In general it seems to be faster to create elements and manipulate them when they aren't attached to the main DOM; therefore create the entire table first then add it in. In plain javascript I think the code below is basically what you want to achieve..
//mock up the data (this will come from you AJAX call)..
var data = [];
for(var i = 0; i < 200; i++){
var rowData = [];
for(var j = 0; j < 10; j++){
rowData.push("This is a string value");
}
data.push(rowData);
}
//create table..
var table = document.createElement("table");
for(var i = 0; i < data.length; i++){
var rowData = data[i];
var row = document.createElement("tr");
for(var j = 0; j < rowData.length; j++){
var cell = document.createElement("td");
cell.innerHTML = rowData[j];
row.appendChild(cell);
}
table.appendChild(row);
}
//finally append the whole thing..
document.body.appendChild(table);
When I stick this into the console in Safari, it runs in < 1 second so you should be ok.
I suggest you to use DocumentFragment and use native javascript for this kind of massive DOM manipulation. I prepared an example, you can check it here.
var fragment = document.createDocumentFragment(),
tr, td, i, il, key;
for(i=0,il=data.length;i<il;i++) {
tr = document.createElement('tr');
for(key in data[i]) {
td = document.createElement('td');
td.appendChild( document.createTextNode( data[i][key] ) );
tr.appendChild( td );
}
fragment.appendChild( tr );
}
$('#mytable tbody').append( fragment );
I think it's the fastest way to do such a job.
Most important thing is to create whole table content out of dom and then insert in to table. This one in chrome ends after about 3 to 5ms:
function createTableFromData(data) {
var tableHtml = '';
var currentRowHtml;
for (var i = 0, length = data.length; i < length; i++) {
currentRowHtml = '<tr><td>' + data[i].join('</td><td>') + '</td></tr>';
tableHtml += currentRowHtml;
}
return tableHtml;
}
var textToAppend= createTableFromData(yourData);
$('#myTable').append(textToAppend);
If you have a validating string of JSON from the server and the structure is reliably an array of arrays of strings, the below will allow you to avoid a JSON parse, and instead replace the HTML generation with a constant series of regular expression operations which tend to be implemented in native code that uses native buffers. This should avoid one parse altogether and replace any buffer copies that cost O(n**2) with k, O(n) buffer copies for a constant k.
var jsonContent
= ' [ [ "foo", "bar", "[baz\\"boo\\n]" ], ["1","2" , "3"] ] ';
var repls = { // Equivalent inside a JSON string.
',': "\\u002b",
'[': "\\u005b",
']': "\\u005d"
};
var inStr = false; // True if the char matched below is in a string.
// Make sure that all '[', ']', and ',' chars in JSON content are
// actual JSON punctuation by re-encoding those that appear in strings.
jsonContent = jsonContent.replace(/[\",\[\]]|\\./g, function (m) {
if (m.length === 1) {
if (m === '"') {
inStr = !inStr;
} else if (inStr) {
return repls[m];
}
}
return m;
});
// Prevent XSS.
jsonContent = jsonContent.replace(/&/g, "&")
.replace(/</g, "<");
// Assumes that the JSON generator does not encode '<' as '\u003c'.
// Remove all string delimiters and space outside of strings.
var html = jsonContent
.replace(/\"\s*([,\]])\s*\"?|\s*([\[,])\s*\"/g, "$1$2");
// Introduce the table header and footer.
html = html.replace(/^\s*\[/g, "<table>")
html = html.replace(/]\s*$/g, "</table>")
// Introduce row boundaries.
html = html.replace(/\],?/g, "</tr>")
html = html.replace(/\[/g, "<tr><td>")
// Introduce cell boundaries.
html = html.replace(/,/g, "<td>")
// Decode escape sequences.
var jsEscs = {
'\\n': '\n',
'\\f': '\f',
'\\r': '\r',
'\\t': '\t',
'\\v': '\x0c',
'\\b': '\b'
};
html = html.replace(/\\(?:[^u]|u[0-9A-Fa-f]{4})/g, function (m) {
if (m.length == 2) {
// Second branch handles '\\"' -> '"'
return jsEscs[m] || m.substring(1);
}
return String.fromCharCode(parseInt(m.substring(2), 16));
});
// Copy and paste with the below to see the literal content and the table.
var pre = document.createElement('pre');
pre.appendChild(document.createTextNode(html));
document.body.appendChild(pre);
var div = document.createElement('div');
div.innerHTML = html;
document.body.appendChild(div);
The fastest will look something like this:
var oldTable = document.getElementById('example'),
newTable = oldTable.cloneNode(true);
for(var i = 0; i < json_example.length; i++){
var tr = document.createElement('tr');
for(var j = 0; j < json_example[i].length; j++){
var td = document.createElement('td');
td.appendChild(document.createTextNode(json_example[i][j]));
tr.appendChild(td);
}
newTable.appendChild(tr);
}
oldTable.parentNode.replaceChild(newTable, oldTable);
And should run in milliseconds. Here is an example: http://jsfiddle.net/Paulpro/YhQEC/ It creates 200 table rows each containing 10 td's.
You want to append using elements, not strings, but you don't want to append anything to the DOM until you're done creating the entire structure (to avoid reflow in your loop). So you can clone the original table and append to the clone, then insert the clone after your loop completes.
You will also gain a fair bit of speed by avoiding jQuery and interacting with the DOM directly.
Your code may look like:
var oldTable = document.getElementById('content_table'),
newTable = oldTable.cloneNode(true),
tr, td;
for(var i = 0; i < entries.alumnus.length.length; i++){
tr = document.createElement('tr');
tr.id = 'entry' + i;
tr.className = 'entry';
if(entries.alumnus[i].title){
td = document.createElement('td');
td.id = 'title' + i;
td.className = 'cell';
var span = document.createElement('span');
span.className = 'content';
span.appendChild(document.createTextNode(entries.alumnus[i].title);
td.appendChild(span);
tr.appendChild(td);
tr.appendChild(createFiller(filler));
}
// REST OF ELEMENTS
newTable.appendChild(tr);
}
oldTable.parentNode.replaceChild(newTable, oldTable);
function createFiller(filler){
var td = document.createElement('td');
td.style.width = '5%';
td.appendChild(document.createTextNode(filler);
return td;
}