Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery jqgrid not sorting on client side

Tags:

jquery

jqgrid

The data loads fine into the grid, but it won't sort.

When I click in the table header, the sort arrows appear, but the data's not being sorted.

Thanks.

    $("#CompTable").jqGrid({ 
            url:'BomExplosionInJsonObj.asp'
        ,   datatype: 'json'
        ,   mtype: 'GET'
        ,   height: 400
        ,   colNames:['Part','Description','Src','Std Usage','Usage Inc Scrap','Rate Scrap','UOM','Item','Unit Cost','Stock']
        ,   colModel:[  {name:'COMP1_PART',index:'Part', width:120}
                                ,   {name:'WSCOMPDESC',index:'Desc', width:300}
                                ,   {name:'WSCOMPSRC',index:'Src', width:10}
                                ,   {name:'COMPUSAGE',index:'Usage', width:80, align:"right",sorttype:"float"}
                                ,   {name:'WSGROSSQTY',index:'TotUsage', width:80, align:"right",sorttype:"float"}
                                ,   {name:'COMPRATE_SCRAP',index:'Rate Scrap', width:80, align:"right",sorttype:"float"}
                                ,   {name:'COMPBASIC_UNIT',index:'UOM', width:20}
                                ,   {name:'COMP1_ITEM',index:'Item', width:20}
                                ,   {name:'WSCOMPUNITCOST',index:'UnitCost', width:80, align:"right",sorttype:"float"}
                                ,   {name:'WSCOMPQTYSTOCK',index:'Stock', width:80, align:"right",sorttype:"float"}
                            ]
        ,   jsonReader: {
                root:"rows"
            ,   page: "page"
            ,   total: "total"
            ,   records: "records"
            ,   repeatitems: false
            ,   id: "0"
            }
        ,   multiselect: false
        ,   caption: "Bom Detail"
        ,   rowNum: 10000
        ,   autoencode: true
        ,   loadonce: true
        ,   sortable: true
        ,   loadComplete: function() {jQuery("#CompTable").trigger("reloadGrid");}// Call to fix client-side sorting
    });
});

JSON Data being returned (as read from firebug).

    {
     "total":"1"
    ,"page":"1"
    ,"records":"2"
    , "rows":
      [
       {"ID":1,"WSCOMPDESC":"ZYTEL E101L BLK MOUL ","WSCOMPUNITCOST":7.08,"WSCOMPSRC":"P ","WSCOMPQTYSTOCK":75,"COMPBASIC_UNIT":"KG ","COMPUSAGE":0.0034,"COMPRATE_SCRAP":0,"WSGROSSQTY":0.0034,"COMP1_PART":"1180019 ","COMP1_ITEM":" "
       },
       {"ID":2,"WSCOMPDESC":"INSERT ","WSCOMPUNITCOST":1.89,"WSCOMPSRC":"P ","WSCOMPQTYSTOCK":400,"COMPBASIC_UNIT":"EA ","COMPUSAGE":2,"COMPRATE_SCRAP":0,"WSGROSSQTY":2,"COMP1_PART":"4OWE195689\/ISS 2 ","COMP1_ITEM":" "
       }
      ]
    }
like image 396
Keith Avatar asked May 04 '13 20:05

Keith


1 Answers

You code have many important errors:

  1. colModel contains index properties which are different from the value of name for the same item. It's the main bug. You don't specified any sortname option of jqGrid so the values of index properties will be never seen by the server. If you use loadonce: true then index properties must be the same as the values of name properties. I recommend you don't include index properties at all. In the case index properties will be initialized with the values of name properties
  2. You use wrong value of id property in jsonReader: id: "0". One use such value sometime in case of repeatitems: true. In the case the row will be represented in JSON input as array. So 0 value will be correct because in can be used as index in the array. In case of usage repeatitems: false the items represented rows of data in the JSON input are objects with named properties. So You should use id: "ID" in your case. Moreover you don't need to include in jsonReader the properties which value are default (root:"rows", page: "page") and so on.
  3. The next problem is the usage of unconditional reloadGrid inside of loadComplete. You should understand that loadComplete will be executed on every reloading of the grid (event on local reloading). So it would be wrong making permanent reloading of grid. Moreover usage of reloadGrid inside of loadComplete is bad from another point of view. If you trigger reloadGrid the event will be executed * immediately*, but the grid is not in processing of previous loading. So it would be more correct to trigger reloading inside of setTimeout with some small time interval like 50 ms.
  4. The last recommendation is usage of K&R (Kernighan and Ritchie's) style of writing of the code. It's not so important which style of formatting of the code you use in another computer language and it's not important which one you personally find the most nice to read. JavaScript has it's own rights. One from there is automatic semicolon insertion (see here for example). If you follow K&R you will never have any problems with automatic semicolon insertion.
  5. I recommend you to use height: "auto" if you need display not so much rows and use column templates which could reduce the size of your code and simplify its management.

After described above changing the could will be something like below

var myFloatTemplate = { width: 80, align: "right", sorttype: "float" };

$("#CompTable").jqGrid({
    url: "BomExplosionInJsonObj.asp",
    datatype: "json",
    height: "auto",
    colNames: ["Part", "Description", "Src", "Std Usage", "Usage Inc Scrap", "Rate Scrap", "UOM", "Item", "Unit Cost", "Stock"],
    colModel: [
        {name: "COMP1_PART", width: 120},
        {name: "WSCOMPDESC", width: 300},
        {name: "WSCOMPSRC", width: 40},
        {name: "COMPUSAGE", template: myFloatTemplate},
        {name: "WSGROSSQTY", width: 120, template: myFloatTemplate},
        {name: "COMPRATE_SCRAP", width: 90, template: myFloatTemplate},
        {name: "COMPBASIC_UNIT", width: 60},
        {name: "COMP1_ITEM", width: 60},
        {name: "WSCOMPUNITCOST", template: myFloatTemplate},
        {name: "WSCOMPQTYSTOCK", template: myFloatTemplate}
    ],
    jsonReader: {
        repeatitems: false,
        id: "ID"
    },
    caption: "Bom Detail",
    rowNum: 10000,
    autoencode: true,
    loadonce: true,
    sortable: true,
    sortname: "COMP1_PART",
    //sortorder: "desc",
    loadComplete: function () {
        var $self = $(this);
        if ($self.jqGrid("getGridParam", "datatype") === "json") {
            setTimeout(function () {
                $self.trigger("reloadGrid"); // Call to fix client-side sorting
            }, 50);
        }
    }
});

The corresponding demo is here. Local sorting works and it displays the following results

enter image description here

UPDATED: Starting with version 4.12.0 free jqGrid fork of jqGrid, which I develop, support new forceClientSorting: true option. It works in combination with loadonce: true option and allows first load all the data from the server response, then sort the data locally and only then to display page of the data. It makes the trick with reloading of grid inside of setTimeout, started in loadComplete, described in the answer, not needed. One need just replace the above loadComplete code to one additional option forceClientSorting: true. The option forceClientSorting: true have additional two benefits:

  1. One don't see any flicker after displaying of the first (unsorted) grid;
  2. The performance of the grid is better, especially if it have many rows, because displaying the grid is much slowly as sorting. Moreover the trick with described in the old answer displays the grid, then delete the content (which is slowly too) and then one displays the sorted grid once more.
like image 128
Oleg Avatar answered Nov 06 '22 09:11

Oleg