Anderson Green
Anderson Green

Reputation: 31800

Generate HTML table from 2D JavaScript array

In JavaScript, is it possible to generate an HTML table from a 2D array? The syntax for writing HTML tables tends to be very verbose, so I want to generate an HTML table from a 2D JavaScript array, as shown:

[
  ["row 1, cell 1", "row 1, cell 2"], 
  ["row 2, cell 1", "row 2, cell 2"]
]

would become:

<table border="1">
  <tr>
    <td>row 1, cell 1</td>
    <td>row 1, cell 2</td>
  </tr>
  <tr>
    <td>row 2, cell 1</td>
    <td>row 2, cell 2</td>
  </tr>
</table>

So I'm trying to write a JavaScript function that would return a table from a 2D JavaScript array, as shown:

function getTable(array){
  // take a 2D JavaScript string array as input, and return an HTML table.
}

Upvotes: 53

Views: 171222

Answers (18)

Romul81
Romul81

Reputation: 31

Based on the accepted solution:

function createTable (tableData) {
  const table = document.createElement('table').appendChild(
    tableData.reduce((tbody, rowData) => {
      tbody.appendChild(
        rowData.reduce((tr, cellData) => {
          tr.appendChild(
            document
              .createElement('td')
              .appendChild(document.createTextNode(cellData)).parentNode
          )
          return tr
        }, document.createElement('tr'))
      )
      return tbody
    }, document.createElement('tbody'))
  ).parentNode

  document.body.appendChild(table)
}

createTable([
  ['row 1, cell 1', 'row 1, cell 2'],
  ['row 2, cell 1', 'row 2, cell 2']
])

With a simple change it is possible to return the table as HTML element.

Upvotes: 3

Adam Sassano
Adam Sassano

Reputation: 273

Here is an ES6 / DOM based / one-liner function. This is similar to other answers, but includes simplified and/or corrected code.

const getTable = array => array.reduce((table, row) => table.appendChild(row.reduce((tr, cell) => tr.appendChild(Object.assign(document.createElement('td'), { textContent: cell })).parentNode, document.createElement('tr'))).parentNode, document.createElement('table'));

const getTable = array => array.reduce((table, row) =>
    table.appendChild(row.reduce((tr, cell) =>
        tr.appendChild(Object.assign(document.createElement('td'), { textContent: cell })).parentNode,
        document.createElement('tr')
    )).parentNode,
    document.createElement('table')
);

const tableData = [
    ["row 1, cell 1", "row 1, cell 2"],
    ["row 2, cell 1", "row 2, cell 2"]
];

document.body.append(getTable(tableData));
table,
td {
    border: 1px solid;
}

Upvotes: 0

codingexplorer
codingexplorer

Reputation: 89

React JSX solution:

let array2d = [
  ["row 1, cell 1", "row 1, cell 2"], 
  ["row 2, cell 1", "row 2, cell 2"]
];

Use .map like so:

<table border="1">
{
array2d.map((array) => 
<tr>
<td>{array[0]}</td>
<td>{array[1]}</td>
</tr>
)}
</table>

Upvotes: 0

Max Makhrov
Max Makhrov

Reputation: 18707

For those who do not want to use DOM

function test_makeTableHTML() {
  var array = [
    ['num', 'date', 'text'],
    [1, new Date(), 'foo'],
    [2, new Date(), 'bar'],
  ]
  var htmltable = makeTableHTML_(array);
  console.log(htmltable);
}

/**
 * creates HTML table code
 * ⚠️ not a DOM-element!
 * from 2d array with a header
 * 
 */
function makeTableHTML_(array) {
    var result = "<table border='1' style='border-collapse:collapse'><tr>";
    var header = array[0];
    for (var i = 0; i < header.length; i++) {
      result += "<th>"+header[i]+"</th>";
    }
    result += "</tr>";
    var val;
    for(var i = 1; i<array.length; i++) {
        result += "<tr>";
        for(var j=0; j<array[i].length; j++){
          val = array[i][j];
          if (val instanceof Date) {
            val = formatDate_(val);
          }
            result += "<td>"+val+"</td>";
        }
        result += "</tr>";
    }
    result += "</table>";

    return result;
}
/**
 * converts JS date
 * to human's date
 * 
 */
// https://stackoverflow.com/a/34015511/5372400
function formatDate_(date) {
  var options = { 
    weekday: 'long', 
    year: 'numeric', 
    month: 'long', 
    day: 'numeric' };
  return date.toLocaleDateString("en-US", options);
}

tested with https://html5-editor.net

Upvotes: 2

Ali Khosro
Ali Khosro

Reputation: 1820

let data = [
  ['Title', 'Artist', 'Duration', 'Created'],
  ['hello', 'me', '2', '2019'],
  ['ola', 'me', '3', '2018'],
  ['Bob', 'them', '4.3', '2006']
];

function getCell (cell, type='td') {
        return `<${type}>${cell}</${type}>`
}
function getCells(cells, type='td') {
        return cells.map(cell => getCell(cell, type)).join('');
}

function getRow(row) {
        return `<tr> ${getCell(row[0], 'th')} ${getCells(row.slice(1))} </tr>`
} 
          
function createTable(data) {
  const [headings, ...rows] = data;
      
    return `
          <table>
            <thead>${getCells(headings, 'th')}</thead>
            <tbody>${rows.map(getRow).join('')}</tbody>
          </table>
    `;
}

document.body.insertAdjacentHTML('beforeend', createTable(data));
table { border-collapse: collapse; }
tr { border: 1px solid #dfdfdf; }
th, td { padding: 4px;}

This is the exact copy of @Andy's answer with a slight modification so that the first cell of every row will be th.

Upvotes: 2

Andy
Andy

Reputation: 63524

Here's a version using template literals. It maps over the data creating new arrays of strings build from the template literals, and then adds them to the document with insertAdjacentHTML:

let data = [
  ['Title', 'Artist', 'Duration', 'Created'],
  ['hello', 'me', '2', '2019'],
  ['ola', 'me', '3', '2018'],
  ['Bob', 'them', '4.3', '2006']
];

function getCells(data, type) {
  return data.map(cell => `<${type}>${cell}</${type}>`).join('');
}

function createBody(data) {
  return data.map(row => `<tr>${getCells(row, 'td')}</tr>`).join('');
}

function createTable(data) {

  // Destructure the headings (first row) from
  // all the rows
  const [headings, ...rows] = data;

  // Return some HTML that uses `getCells` to create
  // some headings, but also to create the rows
  // in the tbody.
  return `
    <table>
      <thead>${getCells(headings, 'th')}</thead>
      <tbody>${createBody(rows)}</tbody>
    </table>
  `;
}

// Bang it altogether
document.body.insertAdjacentHTML('beforeend', createTable(data));
table { border-collapse: collapse; }
tr { border: 1px solid #dfdfdf; }
th, td { padding: 2px 5px 2px 5px;}

Upvotes: 9

chhu79
chhu79

Reputation: 175

My 10cent with ar being the array:

'<table><tr>'+ar.map(e=>'<td>'+e.join('</td><td>')+'</td>').join('</tr><tr>')+'</tr></table>'

Upvotes: 0

zoispag
zoispag

Reputation: 631

One-liner using es6 reduce

function makeTableHTML(ar) {
  return `<table>${ar.reduce((c, o) => c += `<tr>${o.reduce((c, d) => (c += `<td>${d}</td>`), '')}</tr>`, '')}</table>`
}

Upvotes: 5

Dmitry Vasilev
Dmitry Vasilev

Reputation: 6508

Pure functional table without new lines (Just for fun)

const pureFunctionalTable = data => 
    [document.createElement('table')].filter(table => !table.appendChild(
        data.reduce((tbody, row) =>
            !tbody.appendChild(row.reduce((tr, cell) =>
                !tr.appendChild(document.createElement('td'))
                   .appendChild(document.createTextNode(cell)) || tr
                , document.createElement('tr'))
            ) || tbody, document.createElement('tbody'))) || table)[0];


Usage

document.body.appendChild(pureFunctionalTable([
    ['row 1, cell 1', 'row 1, cell 2'],
    ['row 2, cell 1', 'row 2, cell 2']
]));

Upvotes: 2

Punnerud
Punnerud

Reputation: 8021

Generate table and support HTML as input.

Inspired by @spiny-norman https://stackoverflow.com/a/15164796/2326672

And @bornd https://stackoverflow.com/a/6234804/2326672

function escapeHtml(unsafe) {
    return String(unsafe)
         .replace(/&/g, "&amp;")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

function makeTableHTML(myArray) {
    var result = "<table border=1>";
    for(var i=0; i<myArray.length; i++) {
        result += "<tr>";
        for(var j=0; j<myArray[i].length; j++){
            k = escapeHtml((myArray[i][j]));
            result += "<td>"+k+"</td>";
        }
        result += "</tr>";
    }
    result += "</table>";

    return result;
}

Test here with JSFIDDLE - Paste directly from Microsoft Excel to get table

Upvotes: 2

Driton Haxhiu
Driton Haxhiu

Reputation: 117

Here is an example of how you can generate and read data from a matrix m x n... in JavaScript

let createMatrix = (m, n) => {
      let [row, column] = [[], []],
          rowColumn = m * n
      for (let i = 1; i <= rowColumn; i++) {
        column.push(i)
        if (i % n === 0) {
          row.push(column)
          column = []
        }
      }
      return row
    }

let setColorForEachElement = (matrix, colors) => {
  let row = matrix.map(row => {
    let column = row.map((column, key) => {
      return { number: column, color: colors[key] }
    })
    return column
  })
  return row
} 

const colors = ['red', 'green', 'blue', 'purple', 'brown', 'yellow', 'orange', 'grey']
const matrix = createMatrix(6, 8)
const colorApi = setColorForEachElement(matrix, colors)

let table ='<table>'
colorApi.forEach(row => {
  table+= '<tr>'
    row.forEach(column =>  table += `<td style='background: ${column.color};'>${column.number}<td>` )
  table+='</tr>'
})
table+= '</table>'
document.write(table);

Upvotes: 0

holmberd
holmberd

Reputation: 2609

See the fiddle demo to create a table from an array.

function createTable(tableData) {
  var table = document.createElement('table');
  var row = {};
  var cell = {};

  tableData.forEach(function(rowData) {
    row = table.insertRow(-1); // [-1] for last position in Safari
    rowData.forEach(function(cellData) {
      cell = row.insertCell();
      cell.textContent = cellData;
    });
  });
  document.body.appendChild(table);
}

You can use it like this

var tableData = [["r1c1", "r1c2"], ["r2c1", "r2c2"], ["r3c1", "r3c2"]];
createTable(tableData);

Upvotes: 2

cs01
cs01

Reputation: 5763

An es6 version of Daniel Williams' answer:

  function get_table(data) {
    let result = ['<table border=1>'];
    for(let row of data) {
        result.push('<tr>');
        for(let cell of row){
            result.push(`<td>${cell}</td>`);
        }
        result.push('</tr>');
    }
    result.push('</table>');
    return result.join('\n');
  }

Upvotes: 4

jcom
jcom

Reputation: 101

This is holmberd answer with a "table header" implementation

function createTable(tableData) {
  var table = document.createElement('table');
  var header = document.createElement("tr");
  // get first row to be header
  var headers = tableData[0];

  // create table header
  headers.forEach(function(rowHeader){
    var th = document.createElement("th");
    th.appendChild(document.createTextNode(rowHeader));
    header.appendChild(th);
  });      
  console.log(headers);

  // insert table header 
  table.append(header);
  var row = {};
  var cell = {};

  // remove first how - header
  tableData.shift();
  tableData.forEach(function(rowData, index) {
    row = table.insertRow();
    console.log("indice: " + index);
    rowData.forEach(function(cellData) {
      cell = row.insertCell();
            cell.textContent = cellData;
    });
  });
  document.body.appendChild(table);
}

createTable([["row 1, cell 1", "row 1, cell 2"], ["row 2, cell 1", "row 2, cell 2"], ["row 3, cell 1", "row 3, cell 2"]]);

Upvotes: 0

bmavity
bmavity

Reputation: 2508

Here's a function that will use the dom instead of string concatenation.

function createTable(tableData) {
  var table = document.createElement('table');
  var tableBody = document.createElement('tbody');

  tableData.forEach(function(rowData) {
    var row = document.createElement('tr');

    rowData.forEach(function(cellData) {
      var cell = document.createElement('td');
      cell.appendChild(document.createTextNode(cellData));
      row.appendChild(cell);
    });

    tableBody.appendChild(row);
  });

  table.appendChild(tableBody);
  document.body.appendChild(table);
}

createTable([["row 1, cell 1", "row 1, cell 2"], ["row 2, cell 1", "row 2, cell 2"]]);

Upvotes: 87

Josh Powlison
Josh Powlison

Reputation: 781

I know this is an old question, but for those perusing the web like me, here's another solution:

Use replace() on the commas and create a set of characters to determine the end of a row. I just add -- to end of the internal arrays. That way you don't have to run a for function.

Here's a JSFiddle: https://jsfiddle.net/0rpb22pt/2/

First, you have to get a table inside your HTML and give it an id:

<table id="thisTable"><tr><td>Click me</td></tr></table>

Here's your array edited for this method:

thisArray=[["row 1, cell 1__", "row 2, cell 2--"], ["row 2, cell 1__", "row 2, cell 2"]];

Notice the added -- at the end of each array.

Because you also have commas inside of arrays, you have to differentiate them somehow so you don't end up messing up your table- adding __ after cells (besides the last one in a row) works. If you didn't have commas in your cell, this step wouldn't be necessary though.

Now here's your function:

function tryit(){
  document
    .getElementById("thisTable")
    .innerHTML="<tr><td>"+String(thisArray)
    .replace(/--,/g,"</td></tr><tr><td>")
    .replace(/__,/g,"</td><td>");
}

It works like this:

  1. Call your table and get to setting the innerHTML. document.getElementById("thisTable").innerHTML
  2. Start by adding HTML tags to start a row and data. "<tr><td>"
  3. Add thisArray as a String(). +String(thisArray)
  4. Replace every -- that ends up before a new row with the closing and opening of data and row. .replace(/--,/g,"</td></tr><tr><td>")
  5. Other commas signify separate data within rows. So replace all commas the closing and opening of data. In this case not all commas are between rows because the cells have commas, so we had to differentiate those with __: .replace(/__,/g,"</td><td>"). Normally you'd just do .replace(/,/g,"</td><td>").

As long as you don't mind adding some stray characters into your array, it takes up a lot less code and is simple to implement.

Upvotes: 0

Spiny Norman
Spiny Norman

Reputation: 63

Another innerHTML-less version.

function makeTable(array) {
    var table = document.createElement('table');
    for (var i = 0; i < array.length; i++) {
        var row = document.createElement('tr');
        for (var j = 0; j < array[i].length; j++) {
            var cell = document.createElement('td');
            cell.textContent = array[i][j];
            row.appendChild(cell);
        }
        table.appendChild(row);
    }
    return table;
}

Upvotes: 6

Daniel Williams
Daniel Williams

Reputation: 8885

This is pretty easy to do with a double for loop.

function makeTableHTML(myArray) {
    var result = "<table border=1>";
    for(var i=0; i<myArray.length; i++) {
        result += "<tr>";
        for(var j=0; j<myArray[i].length; j++){
            result += "<td>"+myArray[i][j]+"</td>";
        }
        result += "</tr>";
    }
    result += "</table>";

    return result;
}

Upvotes: 46

Related Questions