Book Image

Instant jQuery 2.0 Table Manipulation How-to

By : Charlie Griefer
Book Image

Instant jQuery 2.0 Table Manipulation How-to

By: Charlie Griefer

Overview of this book

When jQuery was introduced, it took the JavaScript world by storm. Years later, it shows no sign of slowing down. Its powerful yet concise syntax helps to simplify tasks that might otherwise be difficult or complex. Whether you're a JavaScript novice or an expert, jQuery is a valuable addition to your toolbox.Instant jQuery 2.0 Table Manipulation How-to shows you how to quickly and easily add style and functionality to your HTML tables. You'll be amazed to see how easy it is. Just don't let your customers know!HTML tables can be boring. Sure, we can make them more stylish with CSS, but users want interactivity. They want to be able to sort columns, see totals, filter data, and page through information in easily digestible chunks. Starting off with a plain HTML table, and an ID and a few class attributes, you will see the transformations occur with just a few lines of jQuery. Instant jQuery 2.0 Table Manipulation How-to progresses to showing you how to highlight specific table cells and filter table data, and even sort columns or page through data. Regardless of your skill level with JavaScript or jQuery, this book will walk you through the deceptively simple steps needed to add functionality and interactivity to your HTML tables.
Table of Contents (7 chapters)

Column sorting – client side (Should know)


Add interactivity to your HTML tables by allowing users to sort table columns.

Getting ready

Stick with the table of the top 15 movies that's been used a few times already. Unlike the last recipe, where we started with an empty table body, this time we'll populate all 15 rows.

How to do it...

  1. Start with the same table that was used in the past few recipes. Because columns will be sorted by clicking on the headers, add <a> elements to the table header text. Each <a> element should have a class of sorter and a unique ID, column_n, where n is the number of the column in the table, starting at 0.

    <table border="1" id="movies">
    <thead>
      <tr>
        <th class="ranking">
          <a href="#" class="sorter" id="column_0">Ranking</a>
        </th>
        <th class="title">
          <a href="#" class="sorter" id="column_1">Movie</a>
        </th>
        <th class="releaseYear">
          <a href="#" class="sorter" id="column_2">Release Year</a>
        </th>
      </tr>
    </thead>
  2. Manually enter all of the movies into rows in the tbody, as follows:

    <tbody>
    <tr>
      <td>1</td>
      <td>Citizen Kane</td>
      <td>1941</td>
    </tr>
    <tr>
      <td>2</td>
      <td>The Godfather</td>
      <td>1972</td>
    </tr>
    …
    <tr>
      <td>15</td>
      <td>2001: A Space Odyssey</td>
      <td>1968</td>
    </tr>
    </tbody>
  3. Finally, add the sorting script, as follows:

    <script type="text/javascript">
    $( document ).ready( function() {
      var tablerows = $( "#movies tbody tr" ).get();
    
      $( "a.sorter" ).click( function( e ) {
        e.preventDefault();
    
        $( "#movies tbody tr" ).remove();
    
        // on which column are we sorting?
        var sort_pos = $( this ).attr( "id" ).split( "_" )[ 1 ];
    
        tablerows.sort( function( a, b ) {
          var atext = $( a ).children( "td" ).eq (sort_pos ).text();
          var btext = $( b ).children( "td" ).eq( sort_pos ).text();
    
          var nums_only = /^\d+$/;
          if ( nums_only.test( atext ) ) atext *= 1;
          if ( nums_only.text( btext ) ) btext *= 1;
    
          if ( atext == btext ) return 0;
          return atext < btext ? -1 : 1;
        });
    
        $.each( tablerows, function( index, tablerow ) {
          $( "#movies tbody" ).append( tablerow );
        });
      });
    
    });
    </script>

How it works...

The first thing to do is to get an array of the table rows. Once again, jQuery makes this ridiculously simple with its built-in get() function. Assign this array to a variable, since it will be referenced later.

var tablerows = $( "#movies tbody tr" ).get();

The selector itself should be familiar by now. The only thing that's new is the addition of .get(), which will create an array of the elements retrieved.

Each of the table headers is surrounded by an <a href> tag with a class attribute of sorter. Listen for a click event on those elements to kick off the function:

$( "a.sorter" ).click( function( e ) {

Because a link was clicked, prevent the default behavior via e.preventDefault(). This was used in previous recipes, so it should be familiar.

As in the previous recipe, clear out all of the table rows within the table body. They'll be added back once they're properly sorted. But before that is done, they need to be removed.

$( "#movies.tbody tr" ).remove();

Now it starts to get a little bit trickier. Determine which column should be sorted. Each of the header links contains a unique ID whose value has a very specific format: column_n, where n is the index of the column. Start the index at 0, so there are IDs column_0, column_1, and column_2.

This specific format will allow you to get the ID via $( this ).attr( "id" ). You can then use JavaScript's built-in split() function to explode the string into an array. split() takes a string argument, which is the substring or pattern on which to split the original string. Use the underscore character to create the array. Because the ID values are all in the column_n format, split() will result in a two element array. The first element, which is at the 0 position, will hold the literal string column. The second element, which is at the 1 position, will hold the column number.

var sort_pos = $( this ).attr( "id" ).split( "_" )[ 1 ];

sort_pos now holds the value 0, 1, or 2, for this table.

Now for the actual sort. JavaScript provides a .sort() method that works on arrays. This isn't jQuery, but standard JavaScript. It's a pretty straightforward algorithm that looks as follows:

array.sort( function( a, b ) {
  if ( a == b ) return 0;
  if ( a < b ) return -1;
  if ( a > b ) return 1;
}

Kick off the sort function on the tablerows array as follows:

tablerows.sort( function( a, b ) {

Unfortunately, that can't be used directly. The array holds table rows. Table row a can't be compared to table row b. The text is in a specific td within table row a and table row b.

var atext = $( a ).children( "td" ).eq( sort_pos ).text();
var btext = $( b ).children( "td" ).eq( sort_pos ).text();

Since both a and b reference specific table rows, drill down into that table row to a specific <td>, and grab the text using jQuery's .text() method.

$( a ) and $( b ) are jQuery hooks into the table rows being compared. This returns an array of the child td elements via .children( "td" ), but a specific td is needed. Remember that a variable sort_pos was set earlier? This is where it gets implemented. Having traversed down to the appropriate td element, use .text() to get its value.

Now run the comparisons for the sort algorithm, but use atext and btext rather than a and b.

if ( atext == btext ) return 0;
if ( atext < btext ) return -1;
if ( atext > btext ) return 1;

With that, the tablerows array is properly sorted. Loop over it and append each row back into the table body:

$.each( tablerows, function(index, tablerow) {
  $( "#movies tbody" ).append( tablerow );
});

There's more...

Note that if the Ranking column is sorted, the results are not 1,2,3,...,15 as one might expect. Rather, the results are 1,10,11,12,13,14,15,2,3,...9. This is also a result of JavaScript being a typeless language. JavaScript is seeing the values as strings, and the string 10 comes before the string 2.

It's a bit of a kludge, but you can do a test to see if the values being compared are numeric. If they are, multiply them by 1. This will leave the value unchanged, but let JavaScript know that these are numeric values.

Prior to the comparison, do the following:

var nums_only = /^\d+$/;

The nums_only variable is a regular expression that checks for one or more digits. Then use JavaScript's native .test() method to test the values. If they're true, multiply the value by 1. This will address the issue of sorting the numeric values.

if ( nums_only.test( atext ) ) atext *= 1; 
if ( nums_only.test( btext ) ) btext *= 1;

This sort only sorts in one direction. Take this opportunity to allow a column heading to be clicked and re-sort the column in the opposite direction. If it was ascending, now sort it in descending order, and vice versa. As a hint, store some variables to allow you to determine which column is currently sorted, and in which direction. Then re-sort in the opposite direction, which would involve a small change to the sort algorithm.