Implementation of NaturalSort Order using jqGrid and asp.net

Around one year ago, I have requirement to make sorting in naturalSort order for one of my web projects (Javascript and jQuery based).
In that project we were using jqGrid a plugin of jquery. Unfortunately, prior versions of jqGrid did not have such a way to provide natural Sorting.

Before, getting more into natural sorting with jqGrid, lets first discuss what is natural sorting:

What is Natural Sorting or naturalSort Order

In simple words we can say, it is nothing but is kind of alphanmeric sorting in natural way. Lets understand this with following example:

 //Needs to sort
 1 3 10 11 1A AA AB 2 A1
 
 //Alphanumeric sorting also known as string sorting
 1 10 1A 11 2 3 AA A1 AB
 
 //Natural sorting
 1 1A 2 3 10 11 A1 AA AB 

So, Natural Sorting is something which seems natural to human, we new 2 should be placed before 11 and after 1, which is possible using naturalSort oder.

Now, gets back to original problem 🙂 I was telling, its not possible sort our data in naturalSort order using jqGrid before its current release version 4.6.0.
I was the main lead for the project and need to solve this issue any how and the challenge is we were not allow to replace jqGrid with other jquery plugins which are having inbuild naturalSort alogorithm

I started research and found some interesting things, I found:
1. Natural sorting algorithm in Javascript: http://js-naturalsort.googlecode.com/svn/trunk/naturalSort.js
2. Unit Tests: http://code.google.com/p/js-naturalsort/source/browse/trunk/unit-tests.html

The above is only the solution for our issue, I was very much excited and started implementation, I used custom formula with jqGrid, unfortunately it was not supported :(.

I posted the issue in many forms and publishing/article places, including stackoverflow: http://stackoverflow.com/questions/14865567/how-to-implement-naturalsort-in-jqgrid.
Unfortunately, I did not get a solution for this issue. And then I approached to Tony Mov the creator of
jqgrid . Afterwards, I logged a bug for this issue at here:
‘NaturalSort’ implementation.

I do not want to to feed my own custom function into jqGrid source file(s). I can’t do that the reason is simple, it will be automatically washed-out
when someone upgrade the jqGrid version. We have only option to wait and see when this issue would be fixed and available with new release of jqGrid.

Finally, on February 08, 2014, Tony Mov announced the new feature here: https://github.com/tonytomov/jqGrid/commit/6131d8a464243d1120278f99a9cdf053246b518f. It is going to make
my life more easy, I was very happy and waiting for new release of jqGrid.

This new feature is having the capability to add our custom sort function in my case I need this:

//3 parmeters comapre values a,b and direction 1 for ascending -1 for descendig

To make this working, Tony Mov, made some corrections to existing javascript natural sorting function as:

/*
 * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
 * Author: Jim Palmer (based on chunking idea from Dave Koelle)
 */
 function naturalSort (a, b, d) {
    if(d===undefined) { d=1; }
    var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
        sre = /(^[ ]*|[ ]*$)/g,
        dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
        hre = /^0x[0-9a-f]+$/i,
        ore = /^0/,
        i = function(s) { return naturalSort.insensitive && (''+s).toLowerCase() || ''+s },
        // convert all to strings strip whitespace
        x = i(a).replace(sre, '') || '',
        y = i(b).replace(sre, '') || '',
        // chunk/tokenize
        xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
        yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
        // numeric, hex or date detection
        xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
        yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
        oFxNcL, oFyNcL;
    // first try and sort Hex codes or Dates
    if (yD)
        if ( xD < yD ) return -d;
        else if ( xD > yD ) return d;
    // natural sorting through split numeric strings and default strings
    for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
        // find floats not starting with '0', string or 0 if not defined (Clint Priest)
        oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
        oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
        // handle numeric vs string comparison - number < string - (Kyle Adams)
        if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? d : -d; }
        // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
        else if (typeof oFxNcL !== typeof oFyNcL) {
            oFxNcL += '';
            oFyNcL += '';
        }
        if (oFxNcL < oFyNcL) return -d;
        if (oFxNcL > oFyNcL) return d;
    }
    return 0;
}

Now, our function is having 3rd parameter which defines the sort order.

Hereunder, I an going to describe following simple steps to use this javascript function with jqGrid (I used Visual Studio 2013, also added a simple html file so, if you want you can just use html file):

  1. Open Visual Studio
  2. Choose template of your choise (I chose asp.net project)
  3. Add latest version of jqGrid using Nuget Packages, it will automatically add supportive jquery files
  4. Add above javascript function as a inline function in same file or in a separate file
  5. Add code of jqgrid to call and make a call to this function

jqgrid code

<script type="text/javascript">
        jQuery(document).ready(function () {
            jQuery("#list4").jqGrid({
                datatype: "local",
                height: 250,
                colNames: ['Inv No', 'Date', 'Natural Sort order', 'Amount', 'Tax', 'Total', 'String Sort'],
                colModel: [{ name: 'id', index: 'id', width: 60, sorttype: "int" },
                { name: 'invdate', index: 'invdate', width: 90, sorttype: "date" },
                { name: 'name', index: 'name', width: 150, sortfunc: naturalSort },
                { name: 'amount', index: 'amount', width: 80, align: "right", sorttype: "float" },
                { name: 'tax', index: 'tax', width: 80, align: "right", sorttype: "float" },
                { name: 'total', index: 'total', width: 80, align: "right", sorttype: "float" },
                { name: 'note', index: 'note', width: 150, sortable: "string" }],

                multiselect: true,
                caption: "NaturalSortOrder using jqrid"
            });

            var mydata = [
            { id: "1", invdate: "2013-10-01", name: "atest", note: "atest", amount: "200.00", tax: "10.00", total: "210.00" },
            { id: "2", invdate: "2013-10-02", name: "Atest", note: "Atest", amount: "300.00", tax: "20.00", total: "320.00" },
            { id: "3", invdate: "2013-09-01", name: "test2", note: "test2", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "4", invdate: "2013-10-04", name: "test", note: "test", amount: "200.00", tax: "10.00", total: "210.00" },
            { id: "5", invdate: "2013-10-05", name: "test2A", note: "test2A", amount: "300.00", tax: "20.00", total: "320.00" },
            { id: "6", invdate: "2013-09-06", name: "test2a", note: "test2a", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "7", invdate: "2013-10-04", name: "Test", note: "Test", amount: "200.00", tax: "10.00", total: "210.00" },
            { id: "8", invdate: "2013-10-03", name: "2", note: "2", amount: "300.00", tax: "20.00", total: "320.00" },
            { id: "9", invdate: "2013-09-01", name: "1", note: "1", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "10", invdate: "2013-09-01", name: "test34", note: "test34", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "9", invdate: "2013-09-01", name: "1test", note: "1test", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "11", invdate: "2013-09-01", name: "10", note: "10", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "12", invdate: "2013-09-01", name: "test33", note: "test33", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "13", invdate: "2013-09-01", name: "Test1", note: "Test1", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "14", invdate: "2013-09-01", name: "BTest", note: "BTest", amount: "400.00", tax: "30.00", total: "430.00" },
            { id: "15", invdate: "2013-09-01", name: "3", note: "3", amount: "400.00", tax: "30.00", total: "430.00" }];


            for (var i = 0; i <= mydata.length; i++)
                jQuery("#list4").jqGrid('addRowData', i + 1, mydata[i]);

        });
    </script>

In above, I added two sorting ways one is string sorting and other is naturalSort order, so, we can understand the actual different between two algorithm or ways of sorting:

Data for sorting

data without sorting

Data available for sorting

Data after string sorting

string sorting

data with string sorting

Data after natural sorting

natural sorting

naturalSort using jqgrid

To use natural sort with jqgrid, we need to write this way:

{ name: 'name', index: 'name', width: 150, sortfunc: naturalSort }

See sortfunc in above, it is telling jqGrid that we need to use naturalSort our custom sort function. Isn’t is easy:)

What to next?

See the latest release and its documentation, here:
1. http://www.trirand.com/jqgridwiki/doku.php?id=wiki:changetwo#jqgrid_4.6.0_changes_and_fixes
2. http://www.trirand.com/blog/?page_id=6

Full source code shown here, is available at:https://github.com/garora/somestuff/tree/develop/jqGridNaturalSortOrder

1 comment on “Implementation of NaturalSort Order using jqGrid and asp.net”

  1. shyam

    Thanks for detailed article I was also looking some kind of solution using jqgrid but never thought this way.
    Can you please provide code in c# too so I can implement the same in my one of windows based project

Leave A Reply