Creating a table from object data

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 would like to create the following table. The format is shown below.

http://jsfiddle.net/gD87t/

I am trying to get elements from an object and trying to add, but am confused with 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 the template engine solve my problem? What is the best way to do this?

+4
source share
7 answers

Here is one way to do this 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; } 

What would look like this:

 var table = document.createElement('table'); addObjectToTable(table,obj); document.body.appendChild(table); 

Please note that the first time you call the tr parameter, it is null, since we always need to create a new line at the top level. When a function is called recursively, the tr parameter is passed from the top level, since the lower levels will basically add to the line of their parent object.

The function returns the number of rows added, so when called back, the caller will know how to set the rowspan value.

Script Link

+4
source

I could not find the answer that processed the circulars, and I also decided to do it without any unnecessary DOM entries. In addition, I did not follow the exact markup requested by the OP because I felt that the nesting tables were more convenient for a recursive operation such as this and served almost the same visual purpose.

So here is the function 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 for testing:

 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.bztest2.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 a table to the DIV (document.getElementById).

http://jsfiddle.net/5RhXF/1/

I hope you find that my implementation is clear.

UPDATE ::

I decided to check this out in the jQuery library and it worked! In addition, functions were printed as their toString value without a good text format. It makes sense, but not very useful. So, I think this is a good and easy way to look at the APIs for frameworks / libraries and what not. Therefore, I added prettify to highlight the syntax of functions, and also added type checking for functions in the table generator and a quick class to get rid of the borders around the prettify field (since there is already a border on the table cell), If someone is interested in the version, for reading / debugging the source, here is the fiddle:

http://jsfiddle.net/5RhXF/7/

+3
source

UPDATED: if you do not need empty cells, the solution may be (check fiddle http://jsfiddle.net/gD87t/11/ )

Example object:

 var obj = { a : { x : 1, y : 2, z : { c : 4, d : 5 } }, b : { x : 1, y : 2, z : 3 } } 

And the procedure for creating the table:

 function merge(rows , inner) { inner.reduce(function (i, p) { rows.push(i) }) } function getRows(o) { var rows = [] if (typeof o == 'object') { for (var k in o) { var innerRows = getRows(o[k]) , firstCell = $('<td />') .text(k) .attr('rowspan',innerRows.length) innerRows[0].prepend(firstCell) rows = rows.concat(innerRows) } } else { var tr = $('<tr />') , td = $('<td />').text(o) tr.append(td) rows.push(tr) } return rows } function buildTable(o, $t) { var rows = getRows(o) $t.append(rows) } buildTable(obj, $('#table2')) 
+2
source

The value for rowspan is the number of properties in the internal object. You can use the Object.keys function to get a list of keys on an object, then use the length property to determine how many properties are:

 for(var i in obj){ var td = document.createElement('td'); td.rowSpan = Object.keys(obj[i]).length; } 
+1
source
 var table = document.createElement('table'); var i, j; var row, cell; for(i in obj) { if(obj.hasOwnProperty(i)) { var row = document.createElement('tr'); var cell = document.createElement('td'); cell.rowSpan = Object.keys(obj[i]).length; cell.innerText = i; row.appendChild(cell); for(j in obj[i]) { if(obj[i].hasOwnProperty(j)) { cell = document.createElement('td'); cell.innerText = j; row.appendChild(cell); cell = document.createElement('td'); cell.innerText = obj[i][j]; row.appendChild(cell); table.appendChild(row); row = document.createElement('tr'); } } } } document.body.appendChild(table); 

Of course, in jQuery this would have looked less verbose. But it looks like you wanted to do this in a simple DOM.

Look at woking

+1
source

Well, it was really difficult, but I think it is done. By the way, I still propose a solution without tables. you can check the working code here

 var obj = { a : { x : 1, y : 2, z : {c:1, d:3} }, b : { x : 1, y : 2, z : 3 } } var table = document.createElement('table'); function createTable (o, parentCells) { for (var key in o) { var row = document.createElement('tr'); var cell = document.createElement('td'); cell.rowSpan = 1; cell.innerText = key; if (typeof o[key] !== "object") { var cellv = document.createElement('td'); cellv.innerText = o[key]; row.appendChild(cell); row.appendChild(cellv); table.appendChild(row); } else { for (var i = 0; i < parentCells.length; i++) { parentCells[i].rowSpan += Object.keys(o[key]).length; } cell.rowSpan += Object.keys(o[key]).length; var newParentCells = new Array(parentCells); newParentCells.push(cell); row.appendChild(cell); table.appendChild(row); createTable(o[key], newParentCells); } } } createTable(obj, []); document.body.appendChild(table); 
0
source

If you want to use document.createElement , as in your question, the easiest way is probably the following:

 function generateTable(o) { var table, tr, td, i, j, l, keys; table = document.createElement('table') for(i in o){ tr = document.createElement('tr'); table.appendChild(tr); td = document.createElement('td'); keys = Object.keys(o[i]); td.rowSpan = keys.length; td.textContent = i; tr.appendChild(td); x=0; for(j=0;j<keys.length;j++) { if(j) { tr = document.createElement('tr'); table.appendChild(tr); } td = document.createElement('td'); td.textContent = keys[j]; tr.appendChild(td); td = document.createElement('td'); td.textContent =o[i][keys[j]]; tr.appendChild(td); } } return table; } 

CAVEAT: Object.keys not available in older browsers, so you will need a polyfill like this:

(taken from MOZILLA DEVELOPER NETWORK )

 if (!Object.keys) { Object.keys = (function () { var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function (obj) { if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object'); var result = []; for (var prop in obj) { if (hasOwnProperty.call(obj, prop)) result.push(prop); } if (hasDontEnumBug) { for (var i=0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); } } return result; }; })(); } 

Alternatively, there is a much simpler polyfill that will cover most cases here:

(taken from tokens )

 if (!Object.keys) Object.keys = function(o) { if (o !== Object(o)) throw new TypeError('Object.keys called on a non-object'); var k=[],p; for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p); return k; } 

Here you can see the fiddle: http://jsfiddle.net/uyJv2/

0
source

Source: https://habr.com/ru/post/1487006/


All Articles