My JSON could have "n" layers of subschema - How can I detect if a key has a subschema under it to prevent if from looping incorrectly as it's doing today? As you can see in my code below I am starting to consider moving the subschemas to arrays, but this feels like a workaround, not the correct approach. Lastly, is it possible to avoid multiple FOR loops to better handle the "n" layers of subschema.
HTML
<table></table>
Javascript
var data = {
"THREE LEVEL": {
"PRODUCTION": {
"One": "http://one.com",
"Two": "http://two.com"
},
"LATEST": {
"alpha": "http://alpha.com",
"omega": "http://omega.com"
},
"STAGE": {
"Apha": "http://alpha.com",
"Bravo": "http://bravo.com",
"Charley": "http://charley.com"
}
},
"TWO LEVEL": {
"PRODUCTION": "http://aaa.com",
"LATEST": "http://bbb.com",
"STAGE": "http://ccc.com"
}
}
var table = document.querySelector('table');
var rows = '';
for (var lev_1 in data) {
rows = '<tr><td>' lev_1 '</td><td></td></tr>'
//if(Array.isArray(data[lev_1])){
for (var lev_2 in data[lev_1]) {
rows = '<tr><td><a href="' data[lev_1][lev_2] '">' lev_2 '</td><td></td></tr>'
//if(Array.isArray(data[lev_1][lev_2])) {
for (var lev_3 in data[lev_1][lev_2]) {
rows = '<tr><td><a href="' data[lev_1][lev_2][lev_3] '">' lev_3 '</td><td></td></tr>'
}
//}
}
//}
}
table.innerHTML = rows;
Current Output
THREE LEVEL
PRODUCTION
One
Two
LATEST
alpha
omega
STAGE
Apha
Bravo
Charley
TWO LEVEL
PRODUCTION
0
1
2
3
4
5
6
7
8
9
10
11
12
13
LATEST
0
1
2
3
4
5
6
7
8
9
10
11
12
13
STAGE
0
1
2
3
4
5
6
7
8
9
10
11
12
13
CodePudding user response:
Use typeof() to determine what kind of element you're dealing with.
If its an object then use Object.keys() to get an array of all of the keys within the object. Then iterate through the keys, testing each with typeof()...
If it's an array, then iterate through each element of the array testing each with typeof()
Rinse and repeat.
The following example should give you a better idea of how to proceed.
var data = {
"THREE LEVEL": {
"PRODUCTION": {
"One": "http://one.com",
"Two": "http://two.com"
},
"LATEST": {
"alpha": "http://alpha.com",
"omega": "http://omega.com"
},
"STAGE": {
"Apha": "http://alpha.com",
"Bravo": "http://bravo.com",
"Charley": "http://charley.com"
}
},
"TWO LEVEL": {
"PRODUCTION": "http://aaa.com",
"LATEST": "http://bbb.com",
"STAGE": "http://ccc.com"
}
}
var table = document.querySelector('table');
var rows = '';
var iterateObject = function(dataObject) {
var keys = Object.keys(dataObject);
keys.forEach(function(key) {
var textArray = [];
var element = dataObject[key];
switch (typeof(element)) {
case 'object':
textArray.push(key)
dumpRow(textArray);
iterateObject(element);
break;
case 'array':
textArray.push(key)
dumpRow(textArray);
iterateArray(element);
break;
default:
dumpElement(dataObject, key);
break;
}
});
};
var iterateArray = function(dataArray) {
dataArray.forEach(function(element) {
switch (typeof(element)) {
case 'object':
iterateObject(element);
break;
case 'array':
iterateArray(element);
break;
default:
var textArray = [];
textArray.push(element)
dumpRow(textArray);
break;
}
});
};
var dumpElement = function(obj, key) {
var textArray = [];
textArray.push(key);
textArray.push(obj[key]);
dumpRow(textArray);
};
var dumpRow = function(textArray) {
var dumpString = '<tr>';
textArray.forEach(function(text) {
dumpString = dumpCell(text);
});
dumpString = '</tr>';
rows = dumpString;
};
var dumpCell = function(dumpText) {
var dumpString = '<td>';
dumpString = dumpText;
dumpString = '</td>';
return dumpString;
};
switch (typeof(data)) {
case 'object':
iterateObject(data);
break;
case 'array':
iterateArray(data);
break;
default:
var textArray = [];
textArray.push(data)
dumpRow(textArray);
break;
}
table.innerHTML = rows;
<html>
<body>
</body>
<table>
</table>
</html>
CodePudding user response:
You should probably make some kind of TableMaker
:
//<![CDATA[
/* js/external.js */
let doc, htm, bod, nav, M, I, mobile, S, Q, TableMaker; // for use on other loads
addEventListener('load', ()=>{
doc = document; htm = doc.documentElement; bod = doc.body; nav = navigator; M = tag=>doc.createElement(tag); I = id=>doc.getElementById(id); mobile = /Mobi/i.test(nav.userAgent);
S = (selector, within)=>{
let w = within || doc;
return w.querySelector(selector);
}
Q = (selector, within)=>{
let w = within || doc;
return w.querySelectorAll(selector);
}
TableMaker = function(object){
this.table = M('table'); this.thead = M('thead'); this.tbody = M('tbody'); this.tfoot = M('tfoot');
this.trMake = ()=>{
return M('tr');
}
this.thMake = textContent=>{
const th = M('th');
th.textContent = textContent;
return th;
}
this.tdMake = textContent=>{
const td = M('td');
td.textContent = textContent;
return td;
}
if(object !== undefined){
let tr, o, n, td;
for(let k in object){
tr = this.trMake();
if(typeof k === 'string'){
tr.appendChild(this.tdMake(k)); this.tbody.appendChild(tr); o = object[k];
if(typeof o === 'string'){
tr.appendChild(this.tdMake(o));
}
else{
n = new TableMaker(object[k]); td = this.tdMake(); td.appendChild(n.table); tr.append(td);
}
}
}
}
this.table.appendChild(this.thead); this.table.appendChild(this.tbody); this.table.appendChild(this.tfoot);
}
// magic below can be put on a separate page - except // end load line
var data = {
"THREE LEVEL": {
"PRODUCTION": {
"One": "http://one.com",
"Two": "http://two.com"
},
"LATEST": {
"alpha": "http://alpha.com",
"omega": "http://omega.com"
},
"STAGE": {
"Apha": "http://alpha.com",
"Bravo": "http://bravo.com",
"Charley": "http://charley.com"
}
},
"TWO LEVEL": {
"PRODUCTION": "http://aaa.com",
"LATEST": "http://bbb.com",
"STAGE": "http://ccc.com"
}
}
const tM = new TableMaker(data);
bod.appendChild(tM.table);
}); // end load
//]]>
table{
border:1px solid #000;
}
td{
border:1px solid #090;
}
You'll notice I've included a small library, as well. Note the recursive nature of TableMaker
.