Working with Tables Using jQuery

By Rob Gravelle

Working with Tables Using jQuery

Since the advent of CSS styling, tables have been relegated back to their original purpose of displaying tabular data - a job that they do extremely well. Unfortunately, their cumbersome tag structure make them difficult to work with in a dynamic way. Difficult for plain JavaScript maybe, but not for jQuery. Its DOM and iteration utility methods allow you to manipulate table cells without having to worry so much about the tags.

Displaying Tabular Data at Runtime

The first challenge with displaying tabular data is that you often don't know how many rows you'll get. I've seen methods that accept the number of rows and columns as arguments, but that information is superfluous to the data itself because table dimensions can be deduced from the data array.

With that in mind, here's a function that I wrote to accept a container element and multi-dimensional array. The outer array contains the rows and in inner ones hold the columns. All of the styling is done using CSS generated by the free online CSSTableGenerator. The jQuery.each() function is an easy way to iterate over an array's elements. The outer one generates the rows, the nested one creates the column elements. The row.append() call has some logic to use table headers ("<th>) instead of regular cells ("<td>) for the first row. Only the "h" and "d" letters set them apart!

function makeTable(container, data) {
    var table = $("<table/>").addClass('CSSTableGenerator');
    $.each(data, function(rowIndex, r) {
        var row = $("<tr/>");
        $.each(r, function(colIndex, c) { 
            row.append($("<t"+(rowIndex == 0 ?  "h" : "d")+"/>").text(c));
        });
        table.append(row);
    });
    return container.append(table);
}

The function, called makeTable(), should be called in the $(document).ready() event so that the DOM has fully loaded. This table contains 4 rows that each contain 3 cities.

$(document).ready(function() {
    var data = [["City 1", "City 2", "City 3"], //headers
                ["New York", "LA", "Seattle"], 
                ["Paris", "Milan", "Rome"], 
                ["Pittsburg", "Wichita", "Boise"]]
    var cityTable = makeTable($(document.body), data);
});

Here is the resulting table in Chrome:

Appending a New Row

There is no one way to append a row to the end of a table because of all the different possible layout options such as the tfoot section and nested tables. If we disregard the rare (and dubious) use of nested tables, we can count on the fact that there should only be one tbody in your table and use the following code to do the job.

function appendTableColumn(table, rowData) {
  var lastRow = $('<tr/>').appendTo(table.find('tbody:last'));
  $.each(rowData, function(colIndex, c) { 
      lastRow.append($('<td/>').text(c));
  });
  
  return lastRow;
}

$(document).ready(function() {
    var table = makeTable(data);
    appendTableColumn(table, ["Calgary", "Ottawa", "Yellowknife"]);
});

The appendTableColumn() function above accepts the table element and an array of cell values. As per jQuery protocol, the new row is returned to enable function chaining. Invoking the appendTo() on the new TR (row) rather than appending it to the TBODY returns the new TR element so that we may append the columns to it. The $.each() iterates over the rowData array and inserts the text into each cell as it is created.

Inspecting the new row element confirms that the proper HTML was generated:

<tbody>
  <tr>...</tr>
  <tr>...</tr>
  <tr>...</tr>
  <tr>...</tr>
  <tr>
    <td>
      Calgary
    </td>
    <td>
      Ottawa
    </td>
    <td>
      Yellowknife
    </td>
  </tr>
</tbody>

Retrieving Table Contents

The same logic that worked so well in creating a table may also be used to retrieve the contents of table cells. In fact, there really isn't a whole lot of difference between the two. The only caveat is that the find() function has to search for both TH and TD cell types. Find() supports multiple selectors, but they have to both be supplied via one string argument and separated by commas.

function getTableData(table) {
    var data = [];
    table.find('tr').each(function (rowIndex, r) {
        var cols = [];
        $(this).find('th,td').each(function (colIndex, c) {
            cols.push(c.textContent);
        });
        data.push(cols);
    });
    return data;
}

Here is the resulting array, including the new row that we appended:

[Array[3], Array[3], Array[3], Array[3], Array[3]]
  0: Array[3]
    0: "City 1"
    1: "City 2"
    2: "City 3"
  1: Array[3]
    0: "New York"
    1: "LA"
    2: "Seattle"
  2: Array[3]
    0: "Paris"
    1: "Milan"
    2: "Rome"
  3: Array[3]
    0: "Pittsburg"
    1: "Wichita"
    2: "Boise"
  4: Array[3]
    0: "Calgary"
    1: "Ottawa"
    2: "Yellowknife"

Conclusion

When it comes to working with HTML tables and data on the client-side, the JavaScript + jQuery combination is hard to beat. That being said, loading tables data procured from the server requires more fire power. For that, you may want to give the DataTables jQuery plug-in a try.


Rob Gravelle resides in Ottawa, Canada, and is the founder of GravelleWebDesign.com. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses.

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His band, Ivory Knight, was rated as one Canada's top hard rock and metal groups by Brave Words magazine (issue #92).



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •  
  •