Skip to content

Instantly share code, notes, and snippets.

@vituchon
Last active January 16, 2022 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vituchon/a34291cfe6a3ce46c57d8b049eac088a to your computer and use it in GitHub Desktop.
Save vituchon/a34291cfe6a3ce46c57d8b049eac088a to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
<script>
class TreeNode {
constructor(valor, parent) {
this.valor = valor;
this.descendants = [];
this.parent = parent;
}
agregarHijo(hijo){
this.descendants.push(hijo);
}
agregarValorExtra(valorExtra){
this.valorExtra = valorExtra;
}
sumarHijosProfundidadInfinita(){
let sumatoria = 0;
if(this.descendants.length === 0){
return 1;
} else {
for (const descendant of this.descendants) {
sumatoria += descendant.sumarHijosProfundidadInfinita();
}
}
return sumatoria;
}
dameElementos(){
if(this.descendants.length === 0){
const medico = document.createElement('td');
medico.textContent = this.valor;
const medicoValor = document.createElement('td');
medicoValor.textContent = this.valorExtra;
return [medico, medicoValor];
} else {
let aux = this.descendants.map(descendant => descendant.dameElementos());
if(Array.isArray(aux[0][0])){
let aux2 = [];
for (const trs of aux) {
aux2.push(...trs);
}
aux = aux2;
}
const tdValor = document.createElement('td');
tdValor.textContent = this.valor;
tdValor.rowSpan = this.sumarHijosProfundidadInfinita();
tdValor.width = '25%';
aux[0].unshift(tdValor);
return aux;
}
}
}
function llenarColumnas(table, columnas){
const tr1 = document.createElement('tr');
const columnsKeys = Object.keys(columnas);
columnsKeys.forEach(columnKey => {
const column = columnas[columnKey];
const columnaElemento = document.createElement('th') ;
columnaElemento.textContent = column.label;
columnaElemento.width = column.size;
tr1.appendChild(columnaElemento);
});
table.width = '100%';
table.appendChild(tr1);
}
function dameLaData(){
return {
'2018': {
'OSDE': {
'medico1': 1,
'medico2': 2
},
'UP': {
'medico1': 1,
'medico2': 2
}
},
'2019': {
'OSDE': {
'medico1': 1,
'medico2': 2
},
'UP': {
'medico1': 1,
'medico2': 2
}
}
};
}
function dameLaData2(){
return {
'2018': {
'OSDE': {
'B2': {
'Juan Gonzalez': 1,
'María López': 2
},
'C5': {
'Pedro Picapiedras': 3,
'Sofía Fraga': 4
}
},
'UP': {
'B2': {
'Juan Gonzalez': 5,
'María López': 6
},
'C5': {
'Pedro Picapiedras': 7,
'Sofía Fraga': 8
}
}
},
'2019': {
'OSDE': {
'B2': {
'Juan Gonzalez': 9,
'María López': 10
},
'C5': {
'Pedro Picapiedras': 11,
'Sofía Fraga': 12
}
},
'UP': {
'B2': {
'Juan Gonzalez': 13,
'María López': 14
},
'C5': {
'Pedro Picapiedras': 15,
'Sofía Fraga': 16
}
}
}
};
}
function isObject(object){
return typeof object === 'object' &&
!Array.isArray(object) &&
object !== null;
}
function armarNodo(data, nodo){
const keys = Object.keys(data);
keys.forEach(key => {
const nodoKey = new TreeNode(key, nodo);
const dataKey = data[key];
if(isObject(dataKey)){
armarNodo(dataKey, nodoKey);
} else {
nodoKey.agregarValorExtra(data[key]);
}
nodo.agregarHijo(nodoKey);
});
}
function dameTrs(nodo){
const futurosTrs = nodo.dameElementos();
const trs = futurosTrs.map(tds => {
const tr = document.createElement('tr');
tds.forEach(td => {
tr.appendChild(td);
});
return tr;
});
return trs;
}
function buildHTMLTable() {
const columnas = {
anio: {label: 'Anio', size: '25%'},
obraSocial: {label: 'Obra social', size: '25%'},
doctor: {label: 'Doctor', size: '25%'},
valor: {label: 'Valor', size: '25%'}
};
const tabla = document.createElement('table');
const columnas2 = {
anio: {label: 'Anio', size: '20%'},
obraSocial: {label: 'Obra social', size: '20%'},
consultorio: {label: 'Consultorio', size: '20%'},
doctor: {label: 'Doctor', size: '20%'},
valor: {label: 'Valor', size: '20%'}
};
const tabla2 = document.createElement('table');
llenarColumnas(tabla, columnas);
llenarColumnas(tabla2, columnas2);
const data = dameLaData();
const arbol = new TreeNode('', null);
armarNodo(data, arbol);
const trs = arbol.descendants.flatMap(descendant => dameTrs(descendant));
trs.forEach(tr => tabla.appendChild(tr));
const mappedResults = document.getElementById('mapped-results');
mappedResults.parentNode.replaceChild(tabla, mappedResults);
const data2 = dameLaData2();
const arbol2 = new TreeNode('', null);
armarNodo(data2, arbol2);
const trs2 = arbol2.descendants.flatMap(descendant => dameTrs(descendant));
trs2.forEach(tr => tabla2.appendChild(tr));
const mappedResults2 = document.getElementById('mapped-results2');
mappedResults2.parentNode.replaceChild(tabla2, mappedResults2);
console.log("ÉXITO");
}
</script>
</head>
<body>
<!-- IDEAL:
<table width="100%">
<tr>
<th width="25%">Anio</th>
<th width="25%">Obra social</th>
<th width="25%">Doctor</th>
<th width="25%">Valor</th>
</tr>
<tr>
<td width="25%" rowspan="4">2018</td>
<td width="25%" rowspan="2">OSDE</td>
<td>medico1</td>
<td>1</td>
</tr>
<tr>
<td>medico2</td>
<td>2</td>
</tr>
<tr>
<td width="25%" rowspan="2">UP</td>
<td>medico1</td>
<td>1</td>
</tr>
<tr>
<td>medico2</td>
<td>2</td>
</tr>
<tr>
<td width="25%" rowspan="4">2019</td>
<td width="25%" rowspan="2">OSDE</td>
<td>medico1</td>
<td>1</td>
</tr>
<tr>
<td>medico2</td>
<td>2</td>
</tr>
<tr>
<td width="25%" rowspan="2">UP</td>
<td>medico1</td>
<td>1</td>
</tr>
<tr>
<td>medico2</td>
<td>2</td>
</tr>
</table>
PRODUCTO: -->
TABLA ORIGINAL:
<div id="mapped-results">
</div>
<hr>
TABLA CON UNA COLUMNA MÁS:
<div id="mapped-results2">
</div>
<button onclick="buildHTMLTable({})">Construir</button>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>A solution for building HTML table from map data</title>
<style>
.result-cell {
padding: 5px;
border: 1px solid black;
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
"use strict";
// do note that html element manipulation is done via jquery routines, so it is need to include a jquery library in this script.
// pasting translated code from: https://www.typescriptlang.org/play?target=2&jsx=0#code/G4QwTgBAJAXCB2BPA3AWAFABdEAcCmEAUgIoCueYiEAvBAihhgGanwDGmAlgPbwRvdWmADJ4QwPAGcAFAFsQOCDDpIAlBADeGCDt2hIAoTQgAGNOl26m3SNIHxJmCAGs8VTn3k51Wi5d32jhCgADbkxl4A2q6IALra-jqBTpySALIKxtj43EzSoeTq1LQA5NwARgBWeBwlCYmcTBDSqRnemvWJ-ILwTgDUtIa9ouJS+SBheKqdlgC+EHghkgS+XQE9-bQAjDO6s7v7fpZgeJikYHxDmJ2HnSzsXLwQ5aScIQAmABIAKmnC3yByiE8HIFMp6D5dskIJhAcDjFBpCUADywoF4AB8JWmRysNma0JiEA8EC8kNxlmhYG4AHdJMYXm93gBBeAsnD4NkAJVpMhiABpSQpom5YoLESjMGAsaocWs0cCAHQKTnvaTUumqcyJQ6JaEKvCstgAC3xtAl704wAAxF58O8ALQnSSkEKYSTY7X+A1G01gRV4WQ4bDSVTKjl4NnSA1am6MXH3Dg8PiMj6s9mqnl0uznE69ADSbmUjjAHgA5oKvEoVIhBWxc5HMFnlCRyJRyXreEFgaNJABhDbGK4jCQyMm7RrNHujgdGYq0Ew+CAAemXQsUqTowQm5EFxpA9Pg3AgACJp1ITxB8ThqThJLskl2nCBMFK+4sQgikaj3jLle93j7EIDxkEpnVdTAHTYD9sUVTA8AAD0wHMwDzTBC0QOUumheBSFkd8Qk-c1v0wX9YJAACgJApFwLdKCYLDeCkOkZF6AxccKQCBteizcNVWkF83w-flcPwj8sMSE4zguCBInrVDGyzeJOPmRZlg6TjHwcJxoMIr9JTIsMKMA4DJFA2jIN0kJYKY5D5LQjCjNfMBpBPDVJBwBAT0Fc9+w2WNNP4bim1pPjIzVKyJP8KleRbMgKEQSJYmMJKvUSaxbEJNxiU8BQOzWbptIgF1yizelaFTFk2WZCNuV5aQBSiGIxXsxTaQCgqIHcxUcFISRjWkRUhpKsqor1YKs301FpWxB8IF1LopPOPh3LSvYbiAA
// functionallity is archieved by invoking `buildHTMLTable(map)` where `map` is a map that follow the given criteria (see * at bootom)
function countLeaves(map) {
var count = 0;
for (const key in map) {
const value = map[key];
const isMap = typeof (value) == 'object';
if (isMap) {
count += countLeaves(value);
}
else {
count += 1;
}
}
return count;
}
function buildHTMLTable(map) {
const table = $('<table>');
for (const key in map) {
const rows = buildAndAppendRows(key, map[key], $('<tr>'));
table.append(rows);
}
const tableAnchor = $('div#mapped-results');
tableAnchor.empty().append(table);
}
function buildAndAppendRows(currentKey, map, currentRow) {
const leavesCount = countLeaves(map);
if (leavesCount === 0) { // this means that "map" is a value (actually a leaf node!), has no "leaves" or props
const attrCell = $('<td>').addClass('result-cell').text(currentKey);
const numCell = $('<td>').addClass('result-cell').text(map);
currentRow.append(attrCell, numCell);
return [currentRow];
}
else {
const cell = $('<td>').addClass('result-cell').text(currentKey).attr("rowspan", leavesCount);
currentRow.append(cell);
const rows = [];
for (const key in map) {
const subRows = buildAndAppendRows(key, map[key], currentRow);
rows.push(...subRows);
currentRow = $('<tr>');
}
return rows;
}
}
var example_map = {
'2020': {
'Downtown': {
'person1': 1,
'person2': 2
},
'Uptown': {
'person1': 3,
'person2': 4
}
},
'2021': {
'Downtown': {
'person1': 5,
'person2': 6
},
'Uptown': {
'person1': 7,
'person2': 8
}
}
}
</script>
</head>
<body>
<div id="mapped-results">
</div>
<hr>
<button onclick="buildHTMLTable(example_map)">Construir</button>
</body>
</html>
@vituchon
Copy link
Author

Build HTML Table from JSON object (Facu Solution) comes from https://github.com/Kvothe838

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment