Create new row for each value that is in an array html javascript

Viewed 450

I have this array:

var output = [[[a], [a1, a3, a5]], [[b], [b1, b2, b3]]]

and i wish to create a table as per below in html with javascript:

a  |  b
-------
a1 | b1
a3 | b2
a5 | b3

but at the moment I'm only getting it like this:

   a     |    b
--------------------
a1,a3,a5 | b1,b2,b3

with this code

  var table = '<table ' + TABLEFORMAT + ' ">';

  for (var row = 0; row < output.length; row++) {

    table += '<tr>';

    for (var col = 0; col < output[row].length; col++) {
      if (output[row][col] === "" || 0) {
        table += '<td>' + '' + '</td>';
      } else
        if (row === 0) {
          table += '<th>' + output[col][row] + '</th>';
        } else {
         table += '<td>' + output[col][row] + '</td>';
        }
    }
    table += '</tr>';
  }

is it possible to do so?

4 Answers

You could transform the data to a table like structure and then create the table.

const
    pad = (array, tag) => array.map(v => `<${tag}>${v}</${tag}>`).join(''),
    raw = [[['a'], ['a1', 'a3', 'a5']], [['b'], ['b1', 'b2', 'b3']]],
    data = raw.reduce((r, [[h], a]) => {
        r.header.push(h);
        a.forEach((v, i) => (r.body[i] = r.body[i] || []).push(v));
        return r;
    }, { header: [], body: [] }),
    table = document.createElement('table');

table.innerHTML = `<table>
    <thead><tr>${pad(data.header, 'th')}</tr></thead>
    <tbody>${pad(data.body.map(a => pad(a, 'td')), 'tr')}
</tbody>`;

document.body.appendChild(table);

You can replace forEach with for..loop if you're not comfortable with forEach.

var table = '<table>';

var output = [
  [
    ["a"],
    ["a1", "a3", "a5"]
  ],
  [
    ["b"],
    ["b1", "b2", "b3"]
  ]
]

output[0].forEach((arr, i, src) => {
  const nextArr = output[1];
  if (i === 0) {
    table += `<tr>`
    table += `<th>${arr[i]} ${nextArr[i]}</th>`
    table += `</tr>`
  } else {
    arr.forEach((el, index, nestedSrc) => {
      table += `<tr>`
      table += `<td>${el} ${nextArr[i][index]}</td>`
      table += `</tr>`
    })
  }
})
table += `</table>`;

document.querySelector("body").innerHTML = table;

The second level array you need to loop and display in a separate table.

function test() {
var output = [[['a'], ['a1', 'a3', 'a5']], [['b'], ['b1', 'b2', 'b3']]];
var table = '<table>';

  for (var row = 0; row < output.length; row++) {

    table += '<tr>';

    for (var col = 0; col < output[row].length; col++) {
      if (output[row][col] === "" || 0) {
        table += '<td>' + '' + '</td>';
      } else
        if (row === 0) {
          table += '<th>' + output[col][row] + '</th>';
        } else {
        tmpArr = output[col][row];
        var tmp = '<table>';
        for(i=0; i<tmpArr.length;i++) {
          tmp +='<tr><td>' + tmpArr[i] + '</td></tr>';
        }
        tmp += '</table>';
         table += '<td>' + tmp + '</td>';
        }
    }
    table += '</tr>';
  }
  document.getElementById('output').innerHTML = table;
}
test();
<div id="output">

</div>

HTML tables are row oriented so the outer loop is for the rows while the inner loop is for each cell within the rows. The way the array of arrays of arrays seems to be column oriented which if not considered an anti-pattern it is most certainly non-standard and excessively unnecessary and difficult.

The demo below generates a <table> with <thead> and <th> and content in the desired positions. The functions are reusable and accepts this pattern:

Array of Arrays of Arrays 
[[[tH], [tD, tD, tD]], [[tH], [tD, tD, tD]], [[tH], [tD, tD, tD]]]

Simplified Linear Array
[tH, tD, tD, tD, tH, tD, tD, tD, tH, tD, tD, tD]

For every tH add +1 to colQty and the tD must be the same amount for each column. So the above example should have colQty=3. Number of columns could be determined programmatically but that would be an entirely new question.

Details are commented in example below

let insane = [
  [['a'], ['a1', 'a3', 'a5', 'a7', 'a9']], 
  [['b'], ['b1', 'b2', 'b3', 'b4', 'b5']], 
  [['c'], ['c2', 'c4', 'c6', 'c8', 'c10']]
];

// Pass in an array of arrays of arrays and number of columns
function columnFlow(arrArrArr, colQty) {
  // Flatten that crazy array in order to avoid dealing with nested data
  const dataArray = arrArrArr.flat().flat();
  // Determine number of rows 
  const rowQty = dataArray.length / colQty;
  // Declare counters used in loops
  let r, c, i;
  
  // Create a HTML table
  const T = `<table><thead></thead><tbody></tbody></table>`;
  const hdr = `<th></th>`;
  const cel = `<td></td>`;
  addHTML(T);
  const table = document.querySelector('table');
  const tHead = table.querySelector('thead');
  const tBody = table.querySelector('tbody');
  
  // Add <tr>, <th>, and <td>
  for (r=0; r < rowQty; r++) {
    if (r === 0) {
      let hRow = tHead.insertRow();
      addHTML(hdr, colQty, hRow);
    } else {
      let dRow = tBody.insertRow();
      addHTML(cel, colQty, dRow);
    }
  }
  
  /*
  Define counter outside of loops in order to access dataArray linearly
  */
  i = 0;
  /*
  Content is inserted into each <th> and <td> by column
  */
  for (c=0; c < colQty; c++) {
    for (r=0; r < rowQty; r++) {
      let cell = table.rows[r].cells[c];
      cell.textContent = dataArray[i];
      i++;
    }
  }
};

/*
Pass a string representing HTML, number of times to be added, and the 
element to add it to. If second parameter is invalid or ignored, it 
defaults to 1. If the third parameter is skipped it defaults to <body>.
*/
function addHTML(string, quantity, node = document.body) {
  let qty = Number.isNaN(quantity) || !quantity ? 1 : quantity;
  for (let i=0; i < qty; i++) {
    node.insertAdjacentHTML('beforeEnd', string);
  }
};
  
columnFlow(insane, 3);
table {
  display: inline-table;
  margin: 10px;
  font: 3ch/1 Consolas;
}

td {
  padding: 6px;
  border-top: 1px black solid;
  text-align: center;
}

th, td {
  border-right: 1px black solid;
}

th:last-child,
td:last-child {
  border-right: 0;
}

Related