Hi, welcome to Word of Mike, my little corner of the internet. I am a Software/Web Developer working in North Yorkshire. I mainly write about programming but my other passion is politics so beware. (click to hide)

2013-11-14 11:38:16 UTC

Responsive Data Grids with JavaScript


All references to responsive tables on the 'net refer to typical tabular data, 'database-style' if you will. We use tables a lot to represent a single row of that data, in what I'll call a data grid. Like this, for instance:

Gender Male DOB (Age) 07/02/1990 (23)
Interests Coding, snooker, sports betting, cooking
Summary Some thing that looks better full width..
Ethnicity White - British Religion None
First Language English English As Additional Language No
Email Address foo@bar.com Telephone Number 01234567

I think this is appropriate data to be represented in a table, and it'd look awful just in one long row. The good thing is that it's ought to be easy to make responsive, you just put every 'key-value' (th and adjacent td) data item in its each row.

I wrote the following simple jQuery plugin to do just this. The default size at which it collapses is below 768px (twitter bootstrap's "extra-small").

(function($) {
  "use strict";

  $.fn.responsiveDataGrid = function(options) {
    return this.each(function() {
      var $this = $(this);
      var $new_table, $old_table;
      var currentSize = 99999;

      // default size below which to pack is 768
      if (!options.packAt)
        options.packAt = '768'

      if (!$this.is("table")) {
        return $this.find("table").each(function(index, item) {
          $(item).responsiveDataGrid(options);
        })
      }

      // check after the initial load
      checkForResize();

      // check subscriptions when window width changes
      $(window).resize(function () {
        checkForResize();            
      });

      // see if subscriptions need to be fired
      function checkForResize() {
        // get the screen width
        var width = $(window).width();

        if (width <= options.packAt && currentSize > options.packAt) {
          currentSize = width;
          packDataGrid();
        } else if (width > options.packAt && currentSize <= options.packAt) {
          currentSize = width;
          unpackDataGrid();
        }
      }

      function packDataGrid() {
        if (!$new_table) {
          $new_table = $this.clone().empty();
          $this.clone().find('tr').each(function(i,tr) {
            var $row = $(tr);
            $row.children('th').each(function(i,th) {
              var $th = $(th);
              var $td = $th.next();
              if ($td.is('td')) {
                var $updated = $('<tr>', {'class':'rdg-wrapped'}).append($th, $td);
                $new_table.append($updated);
              }
            });
          });
        }
        $old_table = $this.replaceWith($new_table);
      }

      function unpackDataGrid() {
        $new_table.replaceWith($old_table);
      }
    });
  }
})(jQuery);

To use, just call .responsiveDataGrid({}) on the table. You can optionally pass "packAt" as an option to change the size at which the table adjusts.

See it in action.