Client side sorting with ASP.NET GridView and jQuery TableSorter

UPDATE If you are looking for a more complete solution including filtering, search, paging, and server side sorting, look at my post on using the datatables plugin with ASP.NET.

Doing some quick data prototyping, I employed the use of the ASP.NET GridView to quickly report on my data objects. As is common, the prototypes quickly took on a life of their own and were asked to be matured into a full on reporting application.

For client-side sorting, I have been using the jQuery Tablesorter plugin. To integrate this plugin, you need simply call the initializing function.

  

  $(document).ready( function(){
    $(".tablesorter").tablesorter();
  });

Out of the box, however, the plugin will not work with the <table> node generated by the ASP.NET Gridview. Comparing the generated output from the GridView with the demo table I realized that the vanilla GridView doesn’t generate the <thead> nodes for the table’s header. To get the proper output, the following changes need to be made in the code behind.

...
gv.Datasource = myDataSource;
gv.DataBind();

//Here's the required code to add
gv.UseAccessibleHeader = true;
if (gv.HeaderRow != null)
{
   //This will tell ASP.NET to render the <thead> for the header row 
   //using instead of the simple <tr>
   gv.HeaderRow.TableSection = TableRowSection.TableHeader; 
} 
...

jQuery Datatables with C# / .NET web services

I just completed a project where I integrated that jQuery Datatables plugin http://datatables.net. The documentation from the Datatables website was helpful but there were a gaps that needed extended documentation.

This particular implementation uses an ASMX service for the underlying service. The plugin is integrated with my <table> with the following call.

 $('#example').dataTable({
        bJQueryUI: true,
        sPaginationType: "full_numbers",
        bProcessing: true,
        bServerSide: true,
        sAjaxSource: '/Services/MyService.asmx/MyWebMethod',
        fnServerData: function (sSource, aoData, fnCallback) {
            var jsonIn = '{ delimiter: "|", delimitedTags: "' + strTags + '", pageSize: 100, skip: ' + aoData[3].value + ', sortColumn: ' + aoData[47].value + ', sortDirection: "' + aoData[48].value + '", echo: ' + aoData[0].value + ' }';
            //alert(jsonIn);

            $.ajax({
                contentType: 'application/json',
                dataType: 'json',
                error: ajaxError,
                type: "POST",
                url: sSource,
                data: jsonIn,
                success: function (msg) {
                    fnCallback(msg.d);
                    searchSuccess(msg.d);
                }
});

The ajax call is to an ASP.NET Web Service (.asmx) so the data needs to be sent as text.
fnCallback is the rendering function for the datatables plugin. The plugin requires the construct passed in to have the following properties:

  • sEcho
  • iTotalRecords
  • iTotalDisplayRecords
  • sColumns (optional)
  • aaData

Following Zack Owens’s advice, I created a server side class that wraps my web service’s response. The properties correspond to the data contract that this plugin expects. For the sEcho property, needs to be populated with the same value that is passed to the fnServerData handler via aoData[0].value otherwise your data table will experience any number of issues re-rendering when you sort or change pages.

    public class FormatedList
    {
        public FormatedList()
        {
        }
        public int sEcho { get; set; }
        public int iTotalRecords { get; set; }
        public int iTotalDisplayRecords { get; set; }
        public List aaData { get; set; }
        public string sColumns { get; set; }
        public void Import(string[] properties)
        {
            sColumns = string.Empty;
            for (int i = 0; i < properties.Length; i++)
            {
                sColumns += properties[i];
                if (i < properties.Length - 1)
                    sColumns += ",";
            }
        }
    }