I've a function in javascript which creates table of properties dynamically:
// update table
PropertyWindow.prototype._update = function (text) {
if (text === void 0) { text = "<no properties to display>"; }
this._propertyWindow.html(text);
};
PropertyWindow.prototype._onModelStructureReady = function () {
this._assemblyTreeReadyOccurred = true;
this._update();
};
// create row for property table
PropertyWindow.prototype._createRow = function (key, property, classStr) {
if (classStr === void 0) { classStr = ""; }
var tableRow = document.createElement("tr");
tableRow.id = "propertyTableRow_" + key + "_" + property;
if (classStr.length > 0) {
tableRow.classList.add(classStr);
}
var keyDiv = document.createElement("td");
keyDiv.id = "propertyDiv_" + key;
keyDiv.innerHTML = key;
var propertyDiv = document.createElement("td");
propertyDiv.id = "propertyDiv_" + property;
propertyDiv.innerHTML = property;
tableRow.appendChild(keyDiv);
tableRow.appendChild(propertyDiv);
return tableRow;
};
I want to take that generated table into json/xml and save this into a new file, how would I do this?
You can basically loop through the generated table like below and convert it into json with the following code
var myRows = [];
var $headers = $("th");
//your table path here inside the selector
var $rows = $("tbody tr").each(function(index) {
$cells = $(this).find("td");
myRows[index] = {};
$cells.each(function(cellIndex) {
myRows[index][$($headers[cellIndex]).html()] = $(this).html();
});
});
// Let's put this in the object like you want and convert to JSON (Note: jQuery will also do this for you on the Ajax request)
var myObj = {};
myObj.myrows = myRows;
alert(JSON.stringify(myObj));
Possible duplicate
I would like to know how to create a table like thisfrom some data in a firebase database like this
There would need to be a column for ID, Title, Number of Answers, Correct Answer and Type. Preferably this should be done using jQuery.
Thank you in advance.
Get data
Read the firebase database documentation and references.
The basic firebase read operation looks like this:
var ref = firebase.database().ref("location");
ref.once("value")
.then(function(snapshot) {
var key = snapshot.key;
var value = snapshot.val();
console.log(key + ": " + value);
});
Of course you have to add scripts for firebase and firebase database before.
If you want to loop through an data you can use forEach function, for example:
var query = firebase.database().ref("location2");
query.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var value = childSnapshot.val();
console.log(key + ": " + value);
});
});
Table
You can create table dynamically using JS - functions like createElement and createDocumentFragment
For example:
var fragment = document.createDocumentFragment();
var animalsArray = ["Elephant", "Dog", "Cat"];
var table = document.createElement("table");
for (var i = 0; i < animalsArray.length; i++) {
var tr = document.createElement("tr");
var td = document.createElement("td");
td.textContent = animalsArray[i];
tr.appendChild(td);
table.appendChild(tr);
}
fragment.appendChild(table);
document.body.appendChild(fragment);
Table built from data in Firebase database
And now connect concepts above together. Create a table. Get data from firebase database. At every ireration over this data: create new table row with cells built from key and value of an element. In example below I used for loop to not duplicate the same operation for every cell.
Full example:
Data tree in Firebase Database:
{
"location2" : {
"hello" : "world",
"hi" : "Mark"
}
}
Code:
var fragment = document.createDocumentFragment();
var table = document.createElement("table");
var query = firebase.database().ref("location2");
query.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var tr = document.createElement("tr");
var trValues = [childSnapshot.key, childSnapshot.val()];
for (var i = 0; i < trValues.length; i++) {
var td = document.createElement("td");
td.textContent = trValues[i];
tr.appendChild(td);
}
table.appendChild(tr);
});
});
fragment.appendChild(table);
document.body.appendChild(fragment);
I'm building a table with HTML and then have created a function which allows me to select a cell. I also have a text field, with a function which will both change the innerText of the cell to the value in the text field and push that value into an array of the data in each table cell. I am then saving it to localStorage.
Here I encounter my error: how can I properly retrieve the data from the localStorage variable and repopulate the table with the values in the array?
Here's my code
omitting the table creation, textEntering, functions because they appear to be working fine
function save() {
localStorage.setItem("tblArrayJson", JSON.stringify(tblArray));
document.getElementById("lblInfo").innerHTML = "Spreadsheet saved.";
}
This is working because in a test function I can print the tblArrayJson in an alert. Next I am trying to load the data back to the table:
function loadSheet() {
var loadedData = JSON.parse(localStorage.getItem("tblArrayJson"));
var loadedTable = document.getElementById("SpreadsheetTable");
var currRow, cell;
alert("the retrieved JSON string contains: " + loadedData);
for (var i = 0; currRow = loadedTable.rows[i]; i++) {
for (var j = 0; cell = currRow.cells[j]; j++) {
cell.innerHTML = loadedData.shift();
}
}
}
The alert displaying the loadedData is working correctly. So what is it about my loop that is failing to insert the array values back into the table? They just stay blank.
Is there a problem with the way I'm using the function? Here is my button with the onclick:
<input id="btnLoad" type="button" onclick="loadSheet();" value="Load" />
localStorage is an object.
A loop through an object for(var key in object) {} is different to a loop through an array for(var i = 0; i < arr.length; i += 1) {}.
If the data looks like
var loadedData = {
0: ["cell1", "cell2", "cell3"],
1: ["cell1", "cell2", "cell3"]
}
the loops should look like
for(var key in loadedData) {
var row = loadedTable.insertRow();
for(var i = 0; i < loadedData[key].length; i += 1) {
var cell = row.insertCell(i);
cell.innerHTML = loadedData[key][i];
}
}
Example
var loadedData = {
0: ["cell1", "cell2", "cell3"],
1: ["cell1", "cell2", "cell3"]
}
function loadSheet() {
//var loadedData = JSON.parse(localStorage.getItem("tblArrayJson"));
var loadedTable = document.getElementById("SpreadsheetTable");
for (var key in loadedData) {
var row = loadedTable.insertRow();
for (var i = 0; i < loadedData[key].length; i += 1) {
var cell = row.insertCell(i);
cell.innerHTML = loadedData[key][i];
}
}
}
loadSheet();
<table id="SpreadsheetTable"></table>
Your for loop is missing the terminating condition. I added that to mine, you're free to modify to fit your needs.
var data = {
0: ["cell1", "cell2", "cell3"],
1: ["cell4", "cell5", "cell6"]
};
// localStorage.tblArrayJson = JSON.stringify(loadedData);
function loadSheet() {
// var data = JSON.parse(localStorage.tblArrayJson);
var table = document.getElementById("SpreadsheetTable");
var row, cell;
// Used Object.keys() to get an array of all keys in localStorage
for (var key of Object.keys(data)) {
row = table.insertRow();
for (var i = 0; i < data[key].length; i++) {
cell = row.insertCell(i);
cell.innerHTML = data[key][i];
}
}
}
loadSheet();
<table id="SpreadsheetTable"></table>
I have a function building a dynamic table. I'm having trouble figuring out how to set each column to a different data set from the database. Right now it just shows the same value in each column.
A little background. I'm building a table with 6 columns and lots of rows (all depends how much data the database has). Right now it's only showing one column in all of the 6 columns, so they repeat.
How can I set each column to a different value for the 6 columns?
function addTable() {
var len = errorTableData.length;
var myTableDiv = document.getElementById("myDynamicTable");
var table = document.createElement('TABLE');
table.border='1';
table.id = "dataTable";
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);
for (var i=0; i<len; i++){
var tr = document.createElement('TR');
tr.className = "rowEditData";
tableBody.appendChild(tr);
for (var j=0; j<6; j++){
var countyName = errorTableData['CountyName'][i];
var stateName = errorTableData['StateName'][i];
var td = document.createElement('TD');
td.className = "mdl-data-table__cell--non-numeric";
td.appendChild(document.createTextNode(countyName));
td.appendChild(document.createTextNode(stateName));
tr.appendChild(td);
}
}
myTableDiv.appendChild(table);
}
Here is the ajax call:
function triggerDataTable(index) {
// Make AJAX requests for model systems
$.ajax({
type: "POST",
url: "qry/getAllData.php",
async: true,
dataType: "html",
data: {ErrorOptions: control.settings.errorOptions},
success: function (result) {
//console.warn(result);
errorData = JSON.parse(result);
//loop through data
var len = errorData.length;
for(i=0; i<len; i++) {
if ('VersionKey' in errorData[i]) {
vKey = (errorData[i]['VersionKey']);
} else if ('ErrorCode' in errorData[i]) {
var errorCode = (errorData[i]['ErrorCode']);
} else if ('SourceKey' in errorData[i]) {
var sourceKey = (errorData[i]['SourceKey']);
} else { //data here
errorTableData = errorData[i];
}
}
addTable();
}
});
}
The errorData is the data from the database. As you can see I've tried to add 2 variables but when I do that it just puts both of them in the same box and repeats throughout the whole table.
It looks like you are printing the exact same data 6 times for each row. You create a td element, then add country and state names to it, but the variable you are using for the index on your data set is coming from your outer loop, so on the inner loop it never changes, and you are literally grabbing the same value every time:
function addTable() {
var len = errorTableData.length;
var myTableDiv = document.getElementById("myDynamicTable");
var table = document.createElement('TABLE');
table.border='1';
table.id = "dataTable";
var tableBody = document.createElement('TBODY');
table.appendChild(tableBody);
for (var i=0; i<len; i++){
// You set i here, presumably to get each row in your dataset
var tr = document.createElement('TR');
tr.className = "rowEditData";
tableBody.appendChild(tr);
for (var j=0; j<6; j++){
var countyName = errorTableData['CountyName'][i];
var stateName = errorTableData['StateName'][i];
// Above, you are using i, not j
var td = document.createElement('TD');
td.className = "mdl-data-table__cell--non-numeric";
td.appendChild(document.createTextNode(countyName));
td.appendChild(document.createTextNode(stateName));
tr.appendChild(td);
}
}
myTableDiv.appendChild(table);
}
It would be easier to help if you could post some json with the data you are getting from the DB
Based on the edit on your post and looking at the success callback, I think you have small problem that can be easily fixed:
First, initialize an empty array for errorTableData
success: function (result) {
errorTableData = [];
In your if/else block:
} else { //data here
errorTableData = errorData[i];
}
Should be:
} else { //data here
errorTableData[i] = errorData[i];
}
Then in your inner loop:
var countyName = errorTableData['CountyName'][i];
var stateName = errorTableData['StateName'][i];
Becomes:
var countyName = errorTableData[i]['CountyName'][j];
var stateName = errorTableData[i]['StateName'][j];
This is just a guess because I can't see the actual 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 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/
UPDATED: if you don't need empty cells solution could 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 routine to build 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'))
The value for the rowspan is the number of properties in the inner object. You can use the Object.keys function to get a list of the keys on the object, then use its length property to determine how many properties there are:
for(var i in obj){
var td = document.createElement('td');
td.rowSpan = Object.keys(obj[i]).length;
}
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, it would look less verbose in jQuery. But it looked like you wanted to do it in plain DOM.
See it woking
well it was really tricky but I think it is done. By the way I still suggest table-less solution. 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);
If you wish to use document.createElement as you do in your question, the easiest way is probably like this:
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 isn't available in older browsers so you'll 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 quite well here:
(Taken from Token Posts)
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;
}
You can see a fiddle of it in action here: http://jsfiddle.net/uyJv2/