Using jQuery To Manipulate and Filter Data

Using jQuery To Manipulate and Filter Data

Jun 10th in JavaScript & AJAX by Noah Hendrix

When a webpage is designed to display large tables of data, a great amount of consideration should be dedicated to allowing the user to sort through the data in a structured manner. In this article, I will go over four techniques: hover effects, zebra rows, filtering, and sorting.

PG

Author: Noah Hendrix

Noah is a Computer Science student at the University of Kansas. His interests include web development in PHP/MySQL and Ruby on Rails. He obsessively follows Tech Startups and has been known to have his own entrepreneurial ambitions. His development environment of choice is Mac OSX using a combination of TextMate and Coda. Find out more about him on twitter (@noahhendrix) or facebook.com/noahhendrix.

Setting Up The Tables

There are some important notes we must address before looking at our Javascript code. The HTML table markup will be like any other table you may have created, except we require two tags that many people omit. The head section of the table must be wrapped in <thead></thead>. The body of the table, where all the data we want to display is kept, must be wrapped in <tbody></tbody>. This little caveat will make it easier for us to distinguish between the data and table headers.

Table
<table cellpadding="1" cellspacing="1" id="resultTable">
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>City</th>
      <th>State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Mannix</td>
      <td>Bolton</td>
    </tr>
    ...
  </tbody>
</table>
  

Zebra Rows

Zebra Rows are a very common data organization technique that are both easy to implement and have a powerful impact. Zebra Rows in essence is alternating the style of odd and even rows to make the data easier to read horizontally. This is highly important with multi-column data so that users can look at one column and easily read the associated data on the same row under other headers. In the examples that I will be using through out this tutorial, I have a list of people with four properties: first name, last name, city, and state. Notice how I have the row colors alternating as well as font color to maximize the effect.

Zebra Rows

Now on to the actual Zebra Rows. The first place to start is an external CSS file linked to the document. The first element to target is the table.

table {
  background-color: white;
  width: 100%;
}
    

This is fairly trivial; we are telling the table background to be white, and to stretch to 100% of the parent element's width. Next we will target the cell elements <td>. Now this might seem odd to some -- why would we target the cells, and not the entire row? Well it turns out that, in terms of cross-browser adoption, it is more effective to target cells when applying background styles.

tbody td {
  background-color: white;
}
tbody td.odd {
  background-color: #666;
  color: white;
}
    

Here we are setting up a class for the "odd" table rows that sets an alternate background-color and font-color. We also set a default style for all td elements which will inherently apply to the "even" rows. This is all the CSS that is required. I told you it was simple! Now let's look at the jQuery code. The power of jQuery selectors makes this just as easy as the CSS code. All we need to do is target the cells and use the addClassName function.

$(document).ready(function() {
  zebraRows('tbody tr:odd td', 'odd');
});


//used to apply alternating row styles
function zebraRows(selector, className)
{
  $(selector).removeClass(className).addClass(className);
}
    

This code, while short, has a few gotchas to consider. First off notice how we abstracted the implementation to a function; this is ideal because if we change the data in the table asynchronously, without a page refresh, then we will want to assure the rows are still alternating style. For the same reason we also invoke the removeClass function so that if a row is initially odd, but becomes even, we are assured that the odd class definition does not remain. This may seem confusing right now, but when we look at filtering later on this will become more clear. For the sake of reusable code we also require that the selector and class name are passed to the function -- so it can be used in projects that have different class names or selector requirements (i.e. a site that has multiple tables only one of which you wish to target). If you review the ready() function, a jQuery function executed when the page is finished loading, you'll see our call to zebraRows(). Here is where we pass in the selector and class name. The selector uses a special jQuery syntax :odd, which will find all odd rows. Then we look for all the child elements of the row that are cells. This code is fairly simple for anyone who has used jQuery previously, but the simplicity should make the code fairly readable to anyone.

Note: While using jQuery to apply alternating row colors is a simple solution, it is not degradable if a user has JavaScript disabled. I would recommend applying the odd class on the server either in PHP code or the static HTML, though this is beyond the scope of this article.

Hover Effect

A really nice effect for users is to highlight the row they are currently hovering upon. This is a great way to single out specific data that they might be interested in. This is dead simple to implement using jQuery, but first a little CSS.

...
td.hovered {
  background-color: lightblue;
  color: #666;
}
...
    

This is all the CSS we need, basically when we hover over a row, we want to make all the cells in that row have a light blue background and a grey font color. The jQuery to make this happen is just as simple.

...
$('tbody tr').hover(function(){
  $(this).find('td').addClass('hovered');
}, function(){
  $(this).find('td').removeClass('hovered');
});
...
    

We are making use of the hover() function in the jQuery library. It takes two arguments that are functions we want executed when the mouse hovers over and when the mouse moves off the element, respectively. When they hover over a row we want to find all the cells within the row and add the hovered class to them. When the mouse leaves the element we want to then remove that class. This is all we have to do to get the hover effect, go try it out!

Hover

Filtering Data

Now the meaty stuff - actually manipulating the data that is shown. If a website calls for many records of data to be displayed, in my example 1000 rows, then it is more than appropriate to offer the user a way to sift through the data. One particularly effective way that has sprung up on the web in recent years as part of the Web2.0/AJAX movement is filtering. This is also something that Apple pushes heavily in there applications such as iTunes. The goal for us is to allow the user to type a search query into a standard text input and live filter the table rows below only showing the ones that contain matching text. This is arguably more advanced then the alternating row styles, but in all reality requires minimal code, due to jQuery's built-in functionality.

First we will write a generic function that takes a selector and a string of text. This function will then search all elements matching that selector looking for the string. If it finds the string, it will show the element and apply a class name of visible to the element, otherwise it hide the element. Why are we applying the class of visible? Well once the items are sorted we will want to run the zebraRows function again, but we need to tell jQuery to ignore the hidden rows, and the best way I have found to do that is apply a class of visible.

The actual searching is done by the JavaScript function, aptly named, search(). Though due to the way the DOM works, if we don't employ the jQuery function, text(), the box will also look at any HTML tags that happen to be in the table row, such as <td>. We will employ a little more functionality by not just searching for the exact string the user has typed, but rather if any of the words in the query are in a row. This is ideal because it allows for "lazy searching", the user isn't required to remember an exact string but rather just parts of it. The search() function takes a regular expression as its parameter, and so we must strip all white space from the beginning and end of our query and put "|" characters in between each word to achieve the OR functionality we desire. Regular expressions are a very complicated topic, and so you will have to take my code at face value or I can refer you to the Regular Expressions for Dummies video series on the ThemeForest blog.

//filter results based on query
function filter(selector, query) {
  query	=	$.trim(query); //trim white space
  query = query.replace(/ /gi, '|'); //add OR for regex query

  $(selector).each(function() {
    ($(this).text().search(new RegExp(query, "i")) < 0) ? $(this).hide().removeClass('visible') : $(this).show().addClass('visible');
  });
}
    

The sixth line is where the magic happens, and probably requires a bit of explanation. Starting at line 5, we are telling the code to loop through all the elements that match the selector, i.e. the rows, and then we want to execute the code on line 6 using each one. Line 6 is a bit complicated if you are new to programming, but it is fairly easy to grasp if we split it up. Think of everything before the question mark as being a question, if the answer to that question is true then execute the code to the left of the colon, but after the question mark. If the answer is false then execute the code after the colon. This is essentially an if statement but in a more concise form known as a ternary operator, and would be no different than writing:

...
  if ($(this).text().search(new RegExp(query, "i")) < 0) {
    $(this).hide().removeClass('visible')
  } else {
   $(this).show().addClass('visible'); 
  }
...
    

The reason we ask if search() returns "< 0" is because it returns the position in the string where query is, and -1 if nothing is matched. Because -1 is always less than zero, we test that condition. In theory there is nothing wrong with checking if it returns (==) -1, but it in practice it is safer to just assure it is less than zero.

Alright now that we have a complete filter function, let's use jQuery events to hook it up to the input. To achieve the live effect we desire the event we want to watch for is when user releases a key while they are focused on the text box, known as keyup in JavaScript. It is important that we set the ID attribute of the input so we can target it using jQuery. Back in our ready function we need to add code after our call to zebraRows().

      <label for="filter">Filter</label>
      <input type="text" name="filter" value="" id="filter" />
    

And the jQuery code:

...
  //default each row to visible
  $('tbody tr').addClass('visible');
  
  $('#filter').keyup(function(event) {
    //if esc is pressed or nothing is entered
    if (event.keyCode == 27 || $(this).val() == '') {
      //if esc is pressed we want to clear the value of search box
      $(this).val('');
			
      //we want each row to be visible because if nothing
      //is entered then all rows are matched.
      $('tbody tr').removeClass('visible').show().addClass('visible');
    }

    //if there is text, lets filter
    else {
      filter('tbody tr', $(this).val());
    }

    //reapply zebra rows
    $('.visible td').removeClass('odd');
    zebraRows('.visible:odd td', 'odd');
...
    

This code is by far the most complex we have seen thus far so we will step through it line by line.

  1. Starting at the addClass('visible') line we are adding a class of visible to each row, because by default they are all visible.
  2. The next line is your standard selector, which in my case is targeting my filter text box and says each time a key is released to execute the following function. Notice that we pass in a parameter called event which has various information about what the user just did, like the key they pressed.
  3. Consequently, the next line of code uses that event parameter, we have an if statement that is checking if the user pressed the esc key. It is important to note that each key is mapped to a number and that is how our code can determine which key the user pressed. This is a nice feature so that users can easily cancel the filter and see all the data again. Many applications with filter boxes utilize this sort of feature, and we want to be sure our application stays inline with what is expected.
  4. In this same if statement we are also taking care of the special case when the value of the filter box is empty (they just hit backspace to remove all characters). In this case we want the user to see all the rows which seems obvious, but we have to explicitly provide for this because the filter function we wrote earlier would look for a row that has no contents and we will hide all the rows that have any content, the exact opposite of what we want!
  5. If either of these conditions are met we want to set the value of the filter box to blank if they pressed esc, it is also executed if the value is blank which doesn't really matter to us.
  6. Next we show all the rows as we wanted to and add a class of visible to all of them. Again we are using the safe practice of first removing any lingering visible class declarations to avoid double setting it. If the value of the filter box is neither empty and the user didn't press escape we want to actually filter the rows.
  7. So after the else statement we call our filter function from earlier providing the rows in our table body to query against.
  8. Finally after we have hidden and shown the appropriate rows, we want to reapply zebraRows to the remaining visible rows. First we remove any lingering odd class declarations to take care of the cases where a row was odd and becomes even. The call to zebraRows is the exact same as the first one on page load, except we only care about the ones that are currently visible and odd.
Filter

Note: A good note might be to use CSS to hide the filter box, and right above the keyup call to show it, so users with JavaScript disabled are not confused when they attempt to sort the data, this would look like:

style.css
...
#filter { display: none; }
...
    
application.js
...
$('#filter').show();
...
    

Wow that was a lot of code, feel free to take a tea/coffee break before we move on to sorting...

Column Sorting

Alright all ready? Good, lets go!

As the final task, we are going to allow sorting the table by any of the column headers. This is very standard practice that users anticipate known as click to sort. When the user clicks one of the headers we want to sort the table ascending and if they click again we want to sort descending by that column. This code is quite advanced and not for the faint at heart. The initial concept came from Learning jQuery 1.3. I have re-engineered it to better fit our needs of simplicity though, however if you desire more fine grain control I will refer you to chapter 7 of the book where tables and jQuery are discussed in great detail.

Before we really dive into the actual code it is important that we discuss the concept of how we plan to tackle this problem. We will use JavaScript's internal sort() method that is designed to take an array and sort it using a custom function supplied by the code. In our case we simply want to sort alphabetically and numerically, so we will just compare the two items it supplies and return which order the two should go in based on that design. Because we want to sort both ascending and descending, we will use a CSS class declaration to see what the current state of the sort by that column is and reverse it if necessary. Once we have our array in order we will use the order to re-insert the rows into the table one-by-one. This sounds like a lot, but because of how blazing fast JavaScript is, it will be very seamless to the user. All of this will be tied to the click event of the column headers in the table.

As per usual, let's get the CSS code out of the way, as it is the most straightforward.

th.sortable {
	color: #666;
	cursor: pointer;
	text-decoration: underline;
}
th.sortable:hover { color: black; }
th.sorted-asc, th.sorted-desc  { color: black; }
  

All of our sortable headers will have a class of sortable, and the hover modifier in CSS makes it emulate a hyperlink for users. We also are taking advantage of the CSS class we mentioned about sorted-asc and sorted-desc so that we can show the user the current column that is sorting the table. I didn't include it but this would be a good place to put background images of arrows pointing up and down as a further visual cue to the user. Now we move on the JavaScript code and the complexity of sorting, thankfully made easier with jQuery. The code below belongs in the ready() function we started way back at the beginning. Placing this right above the end of the function is best.

//grab all header rows
$('thead th').each(function(column) {
  $(this).addClass('sortable').click(function(){
    var findSortKey = function($cell) {
      return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
    };
    var sortDirection = $(this).is('.sorted-asc') ? -1 : 1;

    //step back up the tree and get the rows with data
    //for sorting
    var $rows = $(this).parent().parent().parent().find('tbody tr').get();

    //loop through all the rows and find 
    $.each($rows, function(index, row) {
      row.sortKey = findSortKey($(row).children('td').eq(column));
    });

    //compare and sort the rows alphabetically
    $rows.sort(function(a, b) {
    	if (a.sortKey < b.sortKey) return -sortDirection;
    	if (a.sortKey > b.sortKey) return sortDirection;
    	return 0;
    });

    //add the rows in the correct order to the bottom of the table
    $.each($rows, function(index, row) {
    	$('tbody').append(row);
    	row.sortKey = null;
    });

    //identify the column sort order
    $('th').removeClass('sorted-asc sorted-desc');
    var $sortHead = $('th').filter(':nth-child(' + (column + 1) + ')');
    sortDirection == 1 ? $sortHead.addClass('sorted-asc') : $sortHead.addClass('sorted-desc');

    //identify the column to be sorted by
    $('td').removeClass('sorted')
    			.filter(':nth-child(' + (column + 1) + ')')
    			.addClass('sorted');

    $('.visible td').removeClass('odd');
    zebraRows('.visible:even td', 'odd');
  });
});
  

Woo, that is a lot of code. Let's break that down into sizable bits. The first bit of code is grabbing all the headers and looping through them. The first thing it does is add a class of of sortable, and starts to the click bind.

...
//grab all header rows
$('thead th').each(function(column) {
  $(this).addClass('sortable').click(function(){
...
  

Note that this can easily be changed to allow only certain columns to be sortable by removing the addClass() call and changing the selector from 'thead th' to something like 'thead th.sortable'. Of course this requires you to manually specify which of your columns are sortable by adding class="sortable" to the appropriate headers in the HTML code.

The next bit of code is a function declaration tied to a variable. This might seem a bit weird to those unfamiliar to programming, but it is common practice. This allows us to easily reference the function specifically in the context of the header we are working on. That explanation probably is a bit confusing, but the precise reasoning kind of oversteps the scope of this article. The point of the findSortKey function is determine which column we are sorting by, we can do this because we know the element they clicked on is the same index in the table for all the columns we will compare. For instance if they click the third header we want to look at the third column of each row to compare what order to place the rows. After we declare this function we then determine the sort order, ascending or descending. This is done by looking for the class name of 'sorted-asc' in the table header if it is there we know that it is currently sorted as ascending and we need to make descending, otherwise use the default of ascending. This takes care of the case where it is descending and we need to make it ascending again. This bit of code returns 1 or -1, we will explain why later.

...
var findSortKey = function($cell) {
  return $cell.find('.sort-key').text().toUpperCase() + ' ' + $cell.text().toUpperCase();
};
var sortDirection = $(this).is('.sorted-asc') ? -1 : 1;
...
  

Now we want to get that specific column from each row and put it in an array, this is done using the jQuery method of get() which takes the rows and puts them in an array which the sort() function can understand. Because the current selector was the table head we have to step back up the DOM tree 3 places to find table>tbody>tr>td. Seems a little complex, but in reality it is simple. After that we loop through each of the rows we just found and find the column we want to using in sorting. This is done by checking if its index (the number of places starting at 0 from the first column in the table) is equal to the index of the clicked header. This is then passed into the findSortKey function so we can then set a custom attribute called sortKey that contains the column header we are sorting by and the text of the current column we are looking both of which are set to uppercase so the sort is case-insensitive. This is a way we streamline the sorting so that we make it more responsive for large amounts of data.

...
    //for sorting
    var $rows = $(this).parent().parent().parent().find('tbody tr').get();

    //loop through all the rows and find 
    $.each($rows, function(index, row) {
      row.sortKey = findSortKey($(row).children('td').eq(column));
    });
...
  

Next comes the actual sort() function that I have been going on about. This is called on the array of rows we created using get(). The only parameter we pass is the function we want to determine the sorting. That function receives two attributes to compare and returns 1 if the first is greater, -1 if the second is great, and 0 if they are equal. This is where the sortDirection variable comes into play because the way it works is that we set 1 or -1 to it and then multiply either the 1 or -1 the function should return by sortDirection, achieving the ascending/descending affect we desire.

...
//compare and sort the rows alphabetically
$rows.sort(function(a, b) {
	if (a.sortKey < b.sortKey) return -sortDirection;
	if (a.sortKey > b.sortKey) return sortDirection;
	return 0;
});
...
  

The next bit of code simply adds each row from the now sorted array back into the DOM structure. This is done with the append function which is nice because it does not copy the row and place it at the end it actually removes it from the current place in the DOM and places where we tell it, in this case at the end of the table. After it has done this for each element in the array it will have moved each row to its new place. Also to do a bit of cleanup we remove the sortKey attribute we set earlier.

...
//add the rows in the correct order to the bottom of the table
$.each($rows, function(index, row) {
	$('tbody').append(row);
	row.sortKey = null;
});
...
  

We are now moving in to the cleanup stage of our function since all the heavy lifting has been done. Next we grab all the cells in the table body, remove any lingering sorted attributes in the class declarations, and then filter out all but the columns that are the same index as our sorted header and apply the 'sorted' class to them. This is nice for CSS targeting if for instance we wanted to make the column we sort by a different color we could declare this CSS:

...
.sorted { background-color: green; }
...
  

The final thing we do is remove any 'odd' CSS declarations and reapply the Zebra Rows just like we did in the filter part.

...
$('.visible td').removeClass('odd');
zebraRows('.visible:even td', 'odd');
...
  

That is how we do very simple sorting. It is important to note that this will only sort items alphabetically or numerically and does not work with dates or currency for instance. That requires more specialized handling that is beyond our goals of simple table manipulation.

Sorting

Wrap Up

In this article, we learned how to roll our own table manipulation code using jQuery. This is very convenient for both the user and us. The user gets the expected controls for sorting and filtering the data and we have code that is both small and easy to understand. Because we wrote this ourselves, we can now extend it in our own ways. Our method is great for simple manipulation, but if you require the kitchen sink, I recommend taking a look at the Data Tables plugin for jQuery. I'd love to answer any questions in the comments or on Twitter (@noahendrix). Thanks for reading!


Related Posts

Check out some more great tutorials and articles that you might like

Enjoy this Post?

Your vote will help us grow this site and provide even more awesomeness

Plus Members

Source Files, Bonus Tutorials and
More for $9 a month for all TUTS+
sites in one subscription.

Join Now

User Comments

( ADD YOURS )
  1. PG

    Tutorial City June 10th

    Very very useful! thanks for the tutorial ;)

    ( Reply )
  2. PG

    crysfel June 10th

    very good! this is an useful tut! thanks :D

    ( Reply )
  3. PG

    Dylan June 10th

    Useful stuff. I did notice the zebra striping and hover effect could be done more efficiently though.

    Rather than have jQuery apply an .odd class to each cell in an odd row, just have it add the .odd class to the row itself. Your CSS selector could then be:

    tbody tr.odd td{}

    The advantage to this is that jQuery only needs to work on 1 element per row, the , rather than each in every odd row – 4 elements rather than 16 in your example table.

    This same logic can be applied to the hovering effect – rather than run find() to apply to each of the cells, just apply the .hovered class to the row.

    ( Reply )
    1. PG

      Dj June 10th

      I think in the article he already acknowledged that and said that the reason he didn’t do it was because that method did NOT have consistent cross-browser implementation.

      ( Reply )
  4. PG

    Dylan June 10th

    Ugh – grammar mistakes after the fact are annoying. The sentence should read:

    The advantage to this is that jQuery only needs to work on 1 element per row, the , rather than each in every odd row

    ( Reply )
  5. PG

    Dylan June 10th

    Ok, so no spelling mistakes, just code stripping. Nevermind.

    ( Reply )
  6. PG

    Hasanga June 10th

    How about paging?

    Nice tut!

    ( Reply )
    1. PG

      bhaarat June 11th

      how about server-side paging! now that would be an awesome tut. sometimes we have to display huge amounts of data and don’t want to query the DB all at one time. So each time a new page is loaded we would like to send request back to server with two numbers (start and end) based on which the server will send back a sublist. THAT would be cool tut

      ( Reply )
  7. PG

    Bennie Mosher June 10th

    Very very useful. I think that I might have to use this on a site that I am building right now. I will let you know how it works. Thanks!!!

    ( Reply )
  8. PG

    Steffen June 10th

    Thanks for that great tutorial!
    I was just wondering what the following part in the findSortKey-function does:

    $cell.find(’.sort-key’).text().toUpperCase()

    I think it’s useless as there is no sort-key class. Maybe you just forgot removing it after finishing the development?

    Again: thanks a lot, for your great tutorial!

    ( Reply )
  9. PG

    Benjamin June 10th

    Love the subtle shout out to Michigan ;)

    ( Reply )
  10. PG

    Jack F June 10th

    I feel for the hovering you should also add the css code
    tr:hover {}
    as that works in most browsers, and then add the jQuery as well for those older browsers. Nice tutorial none the less.

    ( Reply )
  11. PG

    Jônatan Fróes June 10th

    How about paging? [2]

    Thanks.

    ( Reply )
  12. PG

    rishteria June 10th

    So useful pal, thanx for sharing ;)

    ( Reply )
  13. PG

    Myfacefriends June 10th

    very useful thanks for this tuts!

    ( Reply )
  14. PG

    Dj June 10th

    Excellent tut. Don’t think filter should stand alone however, probably should have at least an option to filter by the value in only one column, like the sort.

    Also, what would your method be of doing pagination?

    ( Reply )
  15. PG

    Eric D. Greene June 10th

    This is so Kick-Ass. Seriously, thanks so much I’ll be trying it the next opportunity I get.

    ( Reply )
  16. PG

    Peace4man June 10th

    Great Job Thanks sur i will use it on my works todays :p

    ( Reply )
  17. PG

    Kevin Jensen June 10th

    That was a freaking sweet tut! Very practical with lots of application.

    ( Reply )
  18. PG

    Devin Rajaram June 10th

    Wow…been a while since I seen tables…forced to use dreamweaver to edit this lol.

    ( Reply )
  19. PG

    Marcus June 10th

    Great tutorial! I have been looking for something like this.

    Is there a way to call the table data from a .csv file? I want to use this for information that is updated regularly in excel.

    ( Reply )
  20. PG

    Phaoloo June 10th

    Really informative and helpful tip. Just thought jQuery is only for layout, now I now it can be used for filtering data.

    ( Reply )
  21. PG

    digyourlove June 10th

    <>has just method like this one !
    Great job!

    ( Reply )
    1. PG

      digyourlove June 10th

      ( Reply )
  22. PG

    digyourlove June 10th

    ???

    ( Reply )
  23. PG

    desu June 10th

    Thank you for this useful tuts. It’s Good :)

    ( Reply )
  24. PG

    Jim Gaudet June 10th

    Sexy, seriously. Somehow when I am in need of something a new tutorial comes out that does it for me. Now, I just need you to tell me how to do this;

    When a user uploads an image to a site, I will resize it to a width of 1024 (our largest size), now I want to build a page to display the photos, but I want them to shrink to 200 x 200 (I know this will not be proportioned, but we need it for the display, kind of like Facebook). I am sure there is some jquery code to do that, I don’t want to install a plugin. Looking to save speed.

    I have searched but your search always shows your Top 50 posts or things like that and its hard to filter.

    Thanks in advance,

    ( Reply )
  25. PG

    Sergio Masellis June 10th

    Wow I literally came on here to see if you guys had a tutorial like this and you just made it. awesome.

    ( Reply )
  26. Will have to take time to look at this and find a project to use it on. Then I`m sure i`ll see the tutorials true beauty.

    Thanks again,

    C

    ( Reply )
  27. PG

    G. Od June 10th

    One of most useful tut I ‘ve ever seen before.

    ( Reply )
  28. PG

    Noah Hendrix June 10th

    Hey, glad to see the tutorial is helping each of you. I apologize for my grammar (why I am an engineering major, not english :]).

    For those asking about pagination I would definitely refer you to the book I reference in the sorting section, Learning jQuery 1.3 It has a great section on using jQuery to make tables more friendly including pagination. I felt like pagination verged on too much for the goal of a simple solution for the majority of websites.

    ( Reply )
  29. PG

    Guillaume June 11th

    Nice tut! Thanks!

    ( Reply )
  30. PG

    Mansour June 11th

    Very very good .really nice tut.
    thank you .

    ( Reply )
  31. PG

    ron June 11th

    hi
    really great tutorial, but i have a problem that i hope someone can help:

    i have the table populated with database entries. all works great.
    then i added a pagination.

    but then when i try to sort the table all the rest of the entries appear.

    what am i doing wrong?

    ron

    ( Reply )
  32. PG

    Max Stanworth June 11th

    Awesome i was thinking about this yesterday, and heres the solution. It would be intresting to here more about paging results like some others mentioned

    ( Reply )
  33. PG

    Rob June 11th

    “Source -> Get The Code”, nice, but where have all the demo’s gone of the tutorials in question? Nothing paints a better picture of the result of the tutorial than a working example. Not just this one but a good few others have been guilty of this lately. :o (

    ( Reply )
  34. PG

    Vasilis June 11th

    Nice tutorial! I really liked it. I changed a little the sort version in order to be simpler. Here it is::

    $(function() {
    $(’table > thead > tr > th’).click(function() {
    //keep a variable conaining the table item
    var $table = $(this).parents(’table:first’);

    //find the index among that the clicked th had (relative to all thead > th)
    var clickedIndex = $table.find(’thead > tr > th’).index($(this));

    //find if asc or dsc
    var asc = $(this).is(’.asc’) ? -1 : 1;

    //get all ths and remove the asc, dsc class. Then, get the clicked th and add the appropriate class
    $(this).parent().children().removeClass(’asc’).removeClass(’dsc’).end().end().addClass((asc == 1) ? ‘asc’ : ‘dsc’);

    //keep the tbody to a variable
    var $tbody = $table.children(’tbody:first’);

    //get all tbody > tr in an array
    var $dataArray = $tbody.find(’> tr’).get();

    //get the td value from the same column that the clicked th is and store its value trimmed and in Upper case.
    //the .cells is an attribute of every tr object and keeps all the td that belong to the tr
    $.each($dataArray, function(index, row) {
    row.sortKey = $.trim($(row.cells[clickedIndex]).text().toUpperCase());
    });

    //sort the array
    $dataArray.sort(function(a, b) {
    if (a.sortKey b.sortKey) return asc;
    return 0;
    });

    //create a string that keeps all the trs in the rigth order. It is both faster, and let us ‘clean’ the tbody
    //and place the new values in 2 commands, so even if the table is huge the user will not notice a gap
    var trs = “”;
    $.each($dataArray, function(index, row) {
    row.sortKey = null;
    //$tbody.append(row);
    trs += “” + $(row).html() + “”;
    });
    $tbody.empty().append(trs);

    });
    });

    ( Reply )
  35. PG

    Sean June 11th

    Awesome! This is perfect for a site I’m working on at the moment, and very easy to implement.

    ( Reply )
  36. PG

    Nick Brown June 11th

    I just had a need for something like this a few days ago, except my solution was slightly less elegant (multiple queries). Thanks for the great tutorial =)

    ( Reply )
  37. PG

    P@W June 11th

    thank so much.

    ( Reply )
  38. PG

    aev June 11th

    Is it possible to use a similar filtering technique to filter floating div’s instead of table rows?

    Does anyone have suggestions on how this code could be changed to accomplish that?

    ( Reply )
    1. PG

      Iva August 21st

      I would like to know the same, as a client requires it.

      ( Reply )
  39. PG

    Matt Fairbrass June 12th

    Your timing of writing this article couldn’t have been more perfect. I am currently working on exactly this topic for a project at work, so you have made my life 100% easier and cut my development time on this part in half.

    Great tutorial, very well written. Thanks again!

    ( Reply )
  40. PG

    FreewareMatter June 12th

    This is very similar to a chapter of Learning jQuery book. Anyway, thank you for this article.

    ( Reply )
    1. PG

      Noah Hendrix June 12th

      I reference that book in my article, particularly the concept for the sort came in part from that chapter.

      ( Reply )
      1. PG

        Karl Swedberg June 16th

        Hey Noah,
        Thanks for mentioning the book. When I was skimming through the code, I thought it looked familiar. Then I saw your reference and link to the Learning jQuery 1.3. Much appreciated!

        Nice tutorial!

  41. PG

    Diego SA June 12th

    Excellent. This one is wicked! Thanks a lot!

    ( Reply )
  42. PG

    Dona Doni Manuel June 14th

    its relay very good tutorial. and its very help full also…….

    thanx a lot…………

    ( Reply )
  43. PG

    kilinkis June 16th

    standing ovation!

    ( Reply )
  44. PG

    skuja June 20th

    What about utf-8 character sorting.. does this script handles it well

    ( Reply )
  45. PG

    Shane Strong June 25th

    I tested out the sample code and really liked what I saw. the only thing that didn’t make since was that if you select a category it multiplies that category. It could be because I used my own table.

    ( Reply )
    1. PG

      phantom November 2nd

      Same Issue, I’m using PHP to get the list from a database… But when you try to sort it, it multiplies on the admin side, and creates bars on the index side…

      Any Solutions to fix this?

      ( Reply )
  46. PG

    Flayer June 29th

    excellent

    tks

    ( Reply )
  47. PG

    Gabriel Tadeu June 29th

    Dont work very well with latin chars like á, ç.. words with this ’special letters’ came after Z :S

    ( Reply )
  48. PG

    Gerard Banasig June 29th

    long tutorial, but great, very useful

    ( Reply )
  49. PG

    pkunzipula July 3rd

    Noah,

    I have tried implementing a pared-down version your code (no striping or sorting) in a Definition List layout, and the textbox filter behaves erratically. Is it possible for you to look at two quick snippets of code and let me know why?

    Otherwise…YOUR code is awesome. Look forward to more of your insights.

    ( Reply )
  50. PG

    ParsaAkbari July 5th

    $(’tbody tr’).removeClass(’visible’).show().addClass(’visible’);

    On filtering data; why are we removing the class visible, showing the element, then adding the class visible.
    Surely this is unnecessary

    ( Reply )
  51. PG

    Leroy Brown July 6th

    Great code, i supplemented it with:
    http://blogs.picnet.com.au/Guido/post/2009/06/29/JQuery-Table-Filter-Plugin.aspx
    For slightly more flexible filtering.

    Good stuff, thanks!

    ( Reply )
  52. PG

    Djerba July 7th

    Great Work :)

    Data Grid would be better displayed !

    Thank you

    ( Reply )
  53. PG

    Mister Ijoi July 8th

    Great example..good job.

    This example make me to explore jquery more deeply.

    thanks

    ( Reply )
  54. PG

    arnoldc July 8th

    thanks! Im looking for more tutorials of yours!…really helpful but some part of the code are really confusing,anyway its cool

    ( Reply )
  55. PG

    emilio July 10th

    The table doesn’t seem to sort numbers at all (I suppose this is because everything is working alphabetically so 10 comes before 2. Any way to tweak this to sort simple integers properly ?

    ( Reply )
  56. PG

    emilio July 10th

    I figured out how to sort only numeric columns vs alpha columns by replacing lines 65 and 66 with the following – does it work for you guys too ?

    //check for all numeric or other type of column then sort accordingly
    if (isNaN(+a.sortKey) && isNaN(+a.sortKey)) {
    if (a.sortKey b.sortKey) return sortDirection;
    }
    else {
    if (+a.sortKey +b.sortKey) return sortDirection;
    }

    ( Reply )
    1. PG

      emilio July 10th

      sorry, my code didnt’t paste properly, feel free to email me and I can send you the code (but you should be able to figure it out from what i posted) – molten_cheese@hotmail.com

      ( Reply )
  57. .parent().parent().parent()…

    there’s gotta be a better way :/

    ( Reply )
    1. PG

      Jeffrey Way July 13th

      There is with parents(’someElement’)

      ( Reply )
  58. PG

    Wesley July 20th

    Very useful! tutorial thanks,

    But I have a question the search works on every table in my page and i only want it to work on one of the tables that i use. Has anyone a idea how you can change that.

    ( Reply )
  59. PG

    gr2 July 28th

    Great tutorial – just adding finishing touches to it..

    One nice addition to it would be to highlight the bit of text that matches the search characters.

    As an initial try, on the filter function, I tried to use:
    $(this).text($(this).text().replace(query, ‘x’ + query + ‘x’));

    and then planned to replace the ‘x’ characters with a span element.

    this will break the search tho..

    Any tips?

    ( Reply )
  60. PG

    Steelpandrummer August 13th

    hello, little bug: “zomi” finds the first row, which is “Merizo”-”Michigan”, there is no separation between the ending TD and the beginning of the next TD

    ( Reply )
  61. PG

    kanna August 25th

    Hello,

    I want to disable sorting for one column. what should I do for that?

    ( Reply )
  62. PG

    Alex September 6th

    Wow…been a while since I seen tables…forced to use dreamweaver to edit this lol.

    ( Reply )
  63. PG

    Alberta September 12th

    this is really nice tutorial and helped me a lot. And i’ve found it one of the best tutorials in this regard.

    I have used it in my site.. But i have one problem the site on which em working it is about census and have a lot of data in table. And when i try to filter it becomes very slow. Is there any way if i want to make filtering fast even for large amount of data.

    Or how to modify this code in order to get improvement.

    ( Reply )
  64. PG

    Gulri September 13th

    Your timing of writing this article couldn’t have been more perfect. I am currently working on exactly this topic for a project at work, so you have made my life 100% easier and cut my development time on this part in half.

    Great tutorial, very well written. Thanks again!

    ( Reply )
  65. PG

    เพชร September 22nd

    I love jquery.

    ( Reply )
  66. PG

    Thibault September 28th

    Why does the program re-add everything at the end of the table everytime I try to sort the table by column ?

    ( Reply )
    1. PG

      Mihael October 15th

      i have the same problem.

      ( Reply )
  67. PG

    Smashou September 29th

    really usefull! Just in time ;)

    ( Reply )
  68. PG

    Kamal October 8th

    good sharing, thanks

    ( Reply )
  1. Arrow
    Gravatar

    Your Name
    October 8th