Halhelms
SIGN UP FOR MY NEWSLETTER
 
 
Halhelms

Shameless Money

Recent Comments

RSS

Subscribe

Learning jQuery, Day 11: Saving Table State with Cookies

We use a simple jQuery tablesorter to allow users to sort tables by various columns, but at times, users want to restrict their view of table rows -- perhaps only viewing rows of a certain type. Today, we'll look at how to do this with some jQuery and POJS (plain old JavaScript).

You can see the finished product at http://dev.citymind.com:8500/test/blog_jquery/day11/index.cfm. If you have JavaScript enabled, you'll see that the table rows will be hidden. Click the various checkboxes to enable rows by the major genre the composer wrote in.

Once you've selected the types you want to see, you can reload the page and your selections will be maintained.

We'll start with a simple table in index.cfm:

<cfsetting showdebugoutput="false">
<cfset genres = {EARLY=1, CLASSICAL=2, ROMANTIC=3, MODERN=4}>
<cfset genreNames = {1="Early", 2="Classical", 3="Romantic", 4="Modern"}>
<cfquery datasource="learnjquery" name="Composers">
   SELECT
      firstName,
      lastName,
      majorGenre,
      yearBorn,
      yearDied
   FROM
      Composers
   ORDER BY majorGenre, lastName
</cfquery>
<html>
   <head>
      <link rel="stylesheet" type="text/css" href="/test/blog_jquery/day11/blue/style.css"></link>
   </head>
   <body>
      <cfoutput>
      <div><cfloop collection="#genreNames#" item="genreNumber"><input type="checkbox" name="selectedGenres" value="#genreNumber#" checked="checked"> #genreNames[genreNumber]#</cfloop></div>
      <table class="tablesorter" id="composers">
         <thead>
            <tr>
               <th>Last Name</th>
               <th>First Name</th>
               <th>Major Genre</th>
               <th>Born</th>
               <th>Died</th>
            </tr>
         </thead>
         <tbody>
         <cfloop query="Composers">
            <tr class="composer" title="#majorGenre#">
               <td>#lastName#</td>
               <td>#firstName#</td>
               <td>#genreNames[majorGenre]#</td>
               <td>#yearBorn#</td>
               <td>#yearDied#</td>
            </tr>
         </cfloop>
         </tbody>
      </table>
      <cfinclude template="index.pgm">
   </cfoutput>
   </body>
</html>

(This is sample code. Of course, in a real situation, you'd likely not have your CFQUERY on the same page.)

To prepare the table for sorting, I create the table using the THEAD and TBODY tags. The table's CLASS attribute will be used to provide styling.

The included page, "index.pgm", has the processing on it:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="/test/blog_jquery/day11/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/test/blog_jquery/day11/cookies.js"></script>

<script type="text/javascript">
   /* set the table up for sorting */
   $('#composers').tablesorter({widthFixed: true});
   
   /* hide/show and set up a cookie for reading later */
   $('input[name=selectedGenres]').click(function(){
      var selectedGenres = new Array();
      $('.composer').hide();
      $('input[name=selectedGenres]:checked').each(function(){
         selectedGenres.push($(this).val());
         $('tr[title=' + $(this).val() + ']').show();
      });
      selectedGenresString = selectedGenres.join(',');
      createCookie('cookieSelectedGenres', selectedGenresString, 7);
   });
   
   /* read the cookie and set the selected checkboxes */
   var cookieSelectedGenres = readCookie('cookieSelectedGenres');
   
   $('.composer').hide();
   $('input[name=selectedGenres]').removeAttr('checked');
   if (cookieSelectedGenres){
      var selectedGenresArray = cookieSelectedGenres.split(',');
      for (var i=0; i<selectedGenresArray.length; i++) {
         $('input[value=' + selectedGenresArray[i] +']').attr('checked', 'checked');
         $('.composer[title=' + selectedGenresArray[i] + ']').show();
      };
   };
</script>

Let's walk through the code.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="/test/blog_jquery/day11/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/test/blog_jquery/day11/cookies.js"></script>

I begin by including the files I'll need, starting with the jQuery library from Google, a tablesorter file, and a JavaScript file for managing cookies.

Once this is done, I'm ready to add processing to the page. This code makes the table into a sortable one:

/* set the table up for sorting */
$('#composers').tablesorter({widthFixed: true});

Now, I'll write code that will operate when a user clicks on one of the checkboxes:

/* hide/show and set up a cookie for reading later */
$('input[name=selectedGenres]').click(function(){
   var selectedGenres = new Array();
   $('.composer').hide();
   $('input[name=selectedGenres]:checked').each(function(){
      selectedGenres.push($(this).val());
      $('tr[title=' + $(this).val() + ']').show();
   });
   selectedGenresString = selectedGenres.join(',');
   createCookie('cookieSelectedGenres', selectedGenresString, 7);
});

When the user clicks a checkbox, I create a new array, "selectedGenres". Next, I hide all the table rows with composers in them. I do this to start with a blank slate.

This code...

$('input[name=selectedGenres]:checked').each(function(){
   selectedGenres.push($(this).val());
   $('tr[title=' + $(this).val() + ']').show();
});

... finds all the checkboxes that have been check and puts the value into the "selectedGenres" array. Then, any composer rows that have a title matching the genre is turned on.

With this code...

selectedGenresString = selectedGenres.join(',');
createCookie('cookieSelectedGenres', selectedGenresString, 7);

... I create a list with the checkbox values. Then, I create a cookie with that string.

That concludes the code that will run when a checkbox is clicked on.

Now I write code that will run when the page loads:

/* read the cookie and set the selected checkboxes */
var cookieSelectedGenres = readCookie('cookieSelectedGenres');

$('.composer').hide();
$('input[name=selectedGenres]').removeAttr('checked');
if (cookieSelectedGenres){
   var selectedGenresArray = cookieSelectedGenres.split(',');
   for (var i=0; i<selectedGenresArray.length; i++) {
      $('input[value=' + selectedGenresArray[i] +']').attr('checked', 'checked');
      $('.composer[title=' + selectedGenresArray[i] + ']').show();
   };
};

I start by reading the cookie -- if one exists. Then, I hide all the composer rows -- again to start with a blank slate.

I then ensure that all checkboxes start off being unchecked. Then, if I got any values from the cookie, I create an array based on the list values of the cookie. Finally, I loop over the saved genres, and turn on any composer rows whose title matches the genre.

Now, if you've followed along this far, you might think, "Since the code that runs when a checkbox is clicked is so similar to the code when the page initially loads, can't I abstract out the commonalities into a function in order not to duplicate code?"

To which, the answer is "Yes. And make sure to post it in a comment when you're done!"

;-)

Zipped files

Comments
Jose's Gravatar Very nice! I'm trying to implement this but I want to show a total number of records every time a checkbox is clicked. Do you have any tips on how this can be done so it refreshes and show the total count for one or more genres every time a genre is clicked?
# Posted By Jose | 7/6/09 6:40 PM
edward's Gravatar Thank you for posting practical, real-world information about using jQuery - useful and much appreciated. have used to find great blogs with useful pieces of information by http://torrents.rapid4me.com search engine, but always search for smth more. really glad to find good ones. when I first tried it, it seemed as if something went wrong. but after more reading everything was ok. that was really helpful
# Posted By edward | 9/23/09 9:15 AM
Jordan's Gravatar Thanks for the post I have been following up on a lot of your posts and like what you have to say

<a href="http://beagletrainingguide.com/beagle-training/&qu... training</a>
# Posted By Jordan | 10/14/09 9:21 AM
 
   
Clicky Web Analytics