I have an object like the one below:
var obj = {
a : {
x : 1,
y : 2,
z : 3
},
b : {
x : 1,
y : 2,
z : 3
}
}
With it, I will like to generate the following table. Format is showed bellow
http://jsfiddle.net/gD87t/
I am trying to get the elements from object and and trying to append but getting confused with the rowSpan value
var tr = document.createElement('tr');
for(var i in obj){
var td = document.createElement('td');
td.rowSpan = ? // Here I am getting confused.
}
Can a template engine solve my problem? What is the best way to do this?
Here's one way of doing it with a recursive function in pure js:
function addObjectToTable(table, obj, tr) {
var rows = 0;
for (key in obj) {
if (tr == null) {
tr = document.createElement('tr');
table.appendChild(tr);
}
var td = document.createElement('td');
td.textContent = key;
tr.appendChild(td);
var value = obj[key];
if (typeof value != 'object') {
var td = document.createElement('td');
td.textContent = value;
tr.appendChild(td);
rows += 1;
}
else {
var subrows = addObjectToTable(table, value, tr);
td.setAttribute('rowspan',subrows);
rows += subrows;
}
tr = null;
}
return rows;
}
Which would be called like this:
var table = document.createElement('table');
addObjectToTable(table,obj);
document.body.appendChild(table);
Note that when first called, the tr parameter is null, since we always have to create a new row at the top level. When the function is called recursively though, the tr parameter is passed in from the upper level since lower levels will intially be adding to the the row of their parent object.
The function returns the number of rows added, so when it is called recusively the caller will know what to set the rowspan value to.
Fiddle link
I couldn't find an answer which handled circulars, and I also decided to do this without any unnecessary DOM writes. Also, I didn't follow the exact mark-up the OP requested because I felt nesting tables was more convenient for a recursive operation such as this- and serves close to the same visual purpose.
So, here's the function I've created:
function dataToTable (data) {
var storage = [];
return (function buildTable (data) {
var table = '<table><tbody>';
var name, value;
// Add the object/array to storage for cirular detection.
storage.push(data);
for (name in data) {
value = data[name];
table += '<tr><td>' + name + '</td><td>';
// If the value is an object we've put in storage (circular)
if (storage.indexOf(value) !== -1) {
table += '<em>Circular</em>';
} else if (typeof value === 'object') {
table += buildTable(value);
} else {
table += value;
}
table += '</td></tr>';
}
return table + '</tbody></table>';
}(data));
}
Here is the object I used to test:
var obj = {
a : {
x : 1,
y : 2,
z : 3
},
b : {
x : 1,
y : 2,
z : {
test1: 0,
test2: {
test3: 1,
test4: ['a','b','c']
}
}
}
};
obj.c = obj;
obj.b.z.test2.test4.push(obj.a);
The function will turn this object into an HTML table. What you do with the table is up to you. On my fiddle, I used the DOM to add the table to a DIV (document.getElementById).
http://jsfiddle.net/5RhXF/1/
I hope you'll find my implementation clear.
UPDATE::
I decided to test this on the jQuery library, and it worked! Except, the functions were printing as their toString value with no good format for text.. Which makes sense, but not very helpful. So, I'm thinking this is a nice and easy way to look through APIs for frameworks/libraries and what-not. Therefore, I added prettify for syntax-highlighting of functions, and also added a type-check for functions in the table generator, and a quick class to get rid of borders around the prettify box (as there's already a border on the table cell). If anyone is interested in the version designed for source-reading/debugging, here's the fiddle:
http://jsfiddle.net/5RhXF/7/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With