Let’s make a table component with JavaScript

In this tutorial, we’ll make a table component with JavaScript. We’ll make it can be populated with any data and add more features to it in the following series.

This is how a table is structured.

Let’s write the overall structure.

// Create a `…


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Gohomewho

In this tutorial, we'll make a table component with JavaScript. We'll make it can be populated with any data and add more features to it in the following series.

This is how a table is structured.
table demo screenshot from MDN

Let's write the overall structure.

// Create a `table` element and add `thead` and `tbody` to it.
function createTable() {
  const table = document.createElement('table')
  const thead = createTableHead()
  const tbody = createTableBody()
  table.appendChild(thead)
  table.appendChild(tbody)
  return table
}

// create a thead element
function createTableHead() {
  const thead = document.createElement('thead')
  const tr = document.createElement('tr')

  // add th of each column to tr

  thead.appendChild(tr)
  return thead
}

// create a tbody element
function createTableBody() {
  const tbody = document.createElement('tbody')

  // add tr of each row of data to tbody

  return tbody
}

Grab the dummy data from https://jsonplaceholder.typicode.com/users and store it in a variable.

const users = [ 
  //...
]

Define the default columns we want to display. we'll make the columns can be toggled on and off in later series.

const nameOfDefaultColumns = [
  'id',
  'name',
  'username',
  'email',
  'phone',
  'website',
]

Add a parameter columns to createTableHead so it can make each th element according to columns.

function createTableHead(columns) {
  const thead = document.createElement('thead')
  const tr = document.createElement('tr')

  // create th element for each column
  columns.forEach(name => {
    const th = document.createElement('th')
    th.textContent = name
    tr.appendChild(th)
  });

  thead.appendChild(tr)
  return thead
}

Add two parameter columns and dataList to createTableBody so it can make tr for each row of dataList and columns of each row.

function createTableBody(columns, dataList) {
  const tbody = document.createElement('tbody')

  // create rows for each item of dataList
  dataList.forEach(eachDataObject => {
    const tr = document.createElement('tr')

    // create cells of each column for the row
    columns.forEach((columnName) => {
      const td = document.createElement('td')
      // display the data of that column
      td.textContent = eachDataObject[columnName]
      tr.appendChild(td)
    })

    tbody.appendChild(tr)
  });

  return tbody
}

Note that we use columns.forEach() to create column headers in createTableHead and create each column data of each row in createTableBody. This guarantees that the data of each column would match.

This is the code at this point.

const user = [ /* https://jsonplaceholder.typicode.com/users */ ]

const nameOfDefaultColumns = [
  'id',
  'name',
  'username',
  'email',
  'phone',
  'website',
]

const table = createTable(nameOfDefaultColumns, users)
document.body.appendChild(table)

function createTable(columns, dataList) {
  const table = document.createElement('table')
  const thead = createTableHead(columns)
  const tbody = createTableBody(columns, dataList)
  table.appendChild(thead)
  table.appendChild(tbody)
  return table
}

function createTableHead(columns) {
  const thead = document.createElement('thead')
  const tr = document.createElement('tr')

  columns.forEach(columnName => {
    const th = document.createElement('th')
    th.textContent = columnName
    tr.appendChild(th)
  });

  thead.appendChild(tr)
  return thead
}

function createTableBody(columns, dataList) {
  const tbody = document.createElement('tbody')

  dataList.forEach(eachDataObject => {
    const tr = document.createElement('tr')

    columns.forEach((columnName) => {
      const td = document.createElement('td')
      td.textContent = eachDataObject[columnName]
      tr.appendChild(td)
    })

    tbody.appendChild(tr)
  });

  return tbody
}

Our result.
the result at this point

We can easily change the columns we want to display.

const nameOfDefaultColumns = [
  'id',
  'name',
  'username',
  'email',
  'phone',
  'website',
  'company' // add this
]

The column appears! But the data is definitely not correct.
company data display [object object]

Because the data was converted to string before assigning to td.textContent, the toString() was called implicitly. When we call toString() on an object, it will return '[object Object]', This is also the reason why sometimes we try to console.log an object but we see '[object Object]', because it is implicitly converted to a string.

// a number
const id = 1
id.toString()
// '1'

// an object
const obj = {}
obj.toString()
// '[object Object]'

This means we need to process the data before assigning to td.textContent. This also means that if we want to display something more complex, we can't use td.textContent because it will only display string.

We need a way to process the data inside createTableBody. But we can't directly process the data because the data from dataList is dynamic. So how do we process the data inside createTableBody but in the meantime control the actual process from outside? It is like how we pass data to createTableBody. This time we want to pass a formatter.

function createTableBody(columns, dataList, columnFormatter) {
  const tbody = document.createElement('tbody')

  dataList.forEach(eachDataObject => {
    const tr = document.createElement('tr')

    columns.forEach((columnName) => {
      const td = document.createElement('td')
      const columnValue = eachDataObject[columnName]
      // if we have a custom formatter for this column
      // we want to use it
      if (columnFormatter && columnFormatter[columnName]) {
        const formatterOfColumn = columnFormatter[columnName]
        if (formatterOfColumn) {
          const formatted = formatterOfColumn(columnValue)
          // append accept both string and node
          td.append(formatted)
        }
      }
      else {
        // otherwise we simply display the "string version" value
        td.textContent = columnValue
      }

      tr.appendChild(td)
    })

    tbody.appendChild(tr)
  });

  return tbody
}

We call createTableBody from createTable, so we also need to add the columnFormatter parameter to createTable in order to pass it.

// add columnFormatter parameter
function createTable(columns, dataList, columnFormatter) {
  const table = document.createElement('table')
  const thead = createTableHead(columns)
  // call createTableBody with columnFormatter
  const tbody = createTableBody(columns, dataList, columnFormatter)
  table.appendChild(thead)
  table.appendChild(tbody)
  return table
}

Define column formatter. An object that each key is the column name and maps to a function that process the column value.

const columnFormatter = {
  'company': (data) => {
    const p = document.createElement('p')
    const strong = document.createElement('strong')
    strong.textContent = ` (${data.catchPhrase})`
    p.append(data.name, strong)
    return p
  },
  'address': (data) => {
    const {
      street,
      suite,
      city,
      zipcode,
    } = data
    // I don't know how people format address in US.
    // Sorry if this is incorrect
    return `${street} ${suite} ${city} ${zipcode}`
  }
}

const table = createTable(nameOfDefaultColumns, users, columnFormatter)
document.body.appendChild(table)

Display all columns with processed values.
screenshot

This is great! We've already done what we need. It should be able to populate any data. There is one last thing I want to do before closing. Let's refactor the code a little bit.

Move the logic that makes table row from createTableBody to a new function createTableRow so the code can be more readable.

function createTableBody(columns, dataList, columnFormatter) {
  const tbody = document.createElement('tbody')

  dataList.forEach(eachDataObject => {
    const tr = createTableRow(columns, eachDataObject, columnFormatter)
    tbody.appendChild(tr)
  });

  return tbody
}

function createTableRow(columns, dataOfTheRow, columnFormatter) {
  const tr = document.createElement('tr')
  columns.forEach((columnName) => {
    const td = document.createElement('td')
    const columnValue = dataOfTheRow[columnName]

    const formatterOfColumn = columnFormatter && columnFormatter[columnName]
    if (formatterOfColumn) {
      const formatted = formatterOfColumn(columnValue)
      td.append(formatted)
    }
    else {
      td.textContent = columnValue
    }

    tr.appendChild(td)
  })

  return tr
}


This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Gohomewho


Print Share Comment Cite Upload Translate Updates
APA

Gohomewho | Sciencx (2022-11-19T09:40:42+00:00) Let’s make a table component with JavaScript. Retrieved from https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/

MLA
" » Let’s make a table component with JavaScript." Gohomewho | Sciencx - Saturday November 19, 2022, https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/
HARVARD
Gohomewho | Sciencx Saturday November 19, 2022 » Let’s make a table component with JavaScript., viewed ,<https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/>
VANCOUVER
Gohomewho | Sciencx - » Let’s make a table component with JavaScript. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/
CHICAGO
" » Let’s make a table component with JavaScript." Gohomewho | Sciencx - Accessed . https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/
IEEE
" » Let’s make a table component with JavaScript." Gohomewho | Sciencx [Online]. Available: https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/. [Accessed: ]
rf:citation
» Let’s make a table component with JavaScript | Gohomewho | Sciencx | https://www.scien.cx/2022/11/19/lets-make-a-table-component-with-javascript/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.