4

I've been having problems getting jqGrid to sort. I'd like to preferable do this sorting on the client, but I'm also willing to make a new call to the database to get the sorted results as well.

I can click on the column headers and the sort arrows change directions, however the data does not change at all.

I've looked over this question, however calling reloadGrid didn't seem to help.

My entire grid is as follows:

var x = $("#grid").jqGrid({
    jsonReader: { root: "rows", repeatitems: false },
    datatype: "json",
    height: 'auto',
    autowidth: true,
    forceFit: true,
    colNames:['ID','Name'],
    colModel:[
        {name:'id', key:true, index:'id', width:60, sorttype:"int", jsonmap:"id"},
        {name:'name', index:'name', width:90,  jsonmap: "name"}
    ],
    caption: "Results",
    loadonce: true,
    sortable: true,
    loadComplete: function() {
        jQuery("#grid").trigger("reloadGrid"); // Call to fix client-side sorting
    }
});

//This data comes from a web service call, hard coding in to test
var jsonData = [
    {id: 1, name: 'Apple'},
    {id: 2, name: 'Banana'},
    {id: 3, name: 'Pear'},
    {id: 4, name: 'Orange'}
];

x[0].addJSONData( { rows: jsonData } );
Community
  • 1
  • 1
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326

3 Answers3

10

If you load unsorted data from the server and want just sort local data once you should not place jQuery("#grid").trigger("reloadGrid"); inside of loadComplete. The callback loadComplete will be called on every sorting or paging of local data too. Moreover it would be better to call jQuery("#grid").trigger("reloadGrid"); inside of setTimeout. In the case the full first loading of the grid will be finished before reloading.

I don't tested, but I suppose the correct code of loadComplete could be about the following

loadComplete: function () {
    var $this = $(this);
    if ($this.jqGrid('getGridParam', 'datatype') === 'json') {
        if ($this.jqGrid('getGridParam', 'sortname') !== '') {
            // we need reload grid only if we use sortname parameter,
            // but the server return unsorted data
            setTimeout(function () {
                $this.triggerHandler('reloadGrid');
            }, 50);
        }
    }
}

In the case the reloadGrid will be called only once at the first load of the grid from the server. At the next call the value of datatype option will be already 'local'.

UPDATED: Free jqGrid is the fork of jqGrid, which I develop starting with the end 2014. It has many new features. One can use the option forceClientSorting: true to force sorting and filtering of data on the client side before the current page of data will be displayed in jqGrid. Thus one can just add forceClientSorting: true option and remove the trick, described in the old answer.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks! This makes sense. I ended up just doing the sorting up on the server and binding new data, this was trivial and works well for my purposes. – Mike Christensen Apr 23 '12 at 20:35
  • @MikeChristensen: You are welcome! Almost any kind of implementation on the server will be quickly as sorting in JavaScript. So the sorting on the server is the best way. – Oleg Apr 23 '12 at 20:41
  • I agree, especially since some of the sorting I had to do involved multiple keys; so I'd have had to figure out how to write custom comparison functions for jqGrid - which I'm sure is possible but I decided to go the simpler route for now. – Mike Christensen Apr 23 '12 at 21:31
  • should'nt it be `$this.jqGrid('getGridParam', 'sortname') == '' ` you are actually checking not equals to. – Rajshekar Reddy Sep 24 '15 at 12:41
  • @Reddy: No. One should check whether the value of `sortname` parameter is not empty string. So one should use `===` (or `!==`) and `""` or `''`. The current code code trigger `reloadGrid` only if loaded data **need be sorted**, so only if `sortname` parameter is not empty string. – Oleg Sep 24 '15 at 12:53
  • @Reddy: By the way I recommend almost always use **Strict Equality Operators** (`===` and `!==` instead of `==` and `!=`) because one typically don't want to make type conversion before comparing. You can verify that `"" == 0` and `"" == false`. The operation `==` is not transitivity: both `'' == 0` and `0 == '0'` are `true`, but `'' == '0'` if `false`!!! So I personally use `==` only in one special case `if (x == null)` which equivalent the code `if (x === null || x === undefined)`. – Oleg Sep 24 '15 at 12:54
1

Found one solution, though not entirely sure why this works. Perhaps someone can provide a better answer.

var x = $("#grid").jqGrid({
    jsonReader: { root: "rows", repeatitems: false },
    datatype: "json",
    height: 'auto',
    autowidth: true,
    forceFit: true,
    colNames:['ID','Name'],
    colModel:[
        {name:'id', key:true, index:'id', width:60, sorttype:"int", jsonmap:"id"},
        {name:'name', index:'name', width:90,  jsonmap: "name"}
    ],
    caption: "Results",

    //Required for client side sorting
    loadonce: true,
    gridComplete: function(){ 
      $("#grid").setGridParam({datatype: 'local'}); 
    }
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
0

loadonce only works with the predefined loaders. If you use datatype as function you should set datatype:local manually after the first loading of the grid with the custom function.

Try something like this:

datatype : function (){
    $.ajax({
    …
    complete :function (…){
                …
                $("#mygrid").setGridParam({datatype:'local'});
        }
    })
},
Jules
  • 14,200
  • 13
  • 56
  • 101