extjs版本2.1

用extjs的分组store加载数据遇到一个问题,首先store定义如下:

var store = new Ext.data.GroupingStore({        reader: new BidResultItemXmlReader(),        url: Ipms.StateAssetOfficeService + '/QueryBidResultItem',        sortInfo: { field: 'id', direction: "DESC" },        groupField: 'groupField'    });

单从字面分析这段代码:从url加载数据,并且按id进行降序排序,然后按groupField字段分组。

但是最终页面展现的数据,却不是这样的,如下图:

而后台发送的数据的确是按id降序排列的。

原因就是对Ext排序、分组不够了解,仅仅从字面上进行臆断。

1.Store.js中加载数据的方法loadRecords()源码如下:

loadRecords : function(o, options, success){    // ...                                                                                                                                                                                                                                               this.applySort(); // 会调用GroupingStore的方法                                                                                                                                                                                                                                               // ..}

2.GroupingStore.js中applySort()源码:

applySort : function(){        Ext.data.GroupingStore.superclass.applySort.call(this);        if(!this.groupOnSort && !this.remoteGroup){            var gs = this.getGroupState();            if(gs && gs != this.sortInfo.field){ // 凶手                this.sortData(this.groupField); // 调用Store的方法            }        }    },

从源码可知,只要我们的排序字段跟分组字段不是相同列的话,他都会再次按分组字段排序。

3.Store.js中sortData()源码:

// privatesortData : function(f, direction){    direction = direction || 'ASC';    var st = this.fields.get(f).sortType;    var fn = function(r1, r2){        var v1 = st(r1.data[f]), v2 = st(r2.data[f]);        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);    };    this.data.sort(direction, fn);    if(this.snapshot && this.snapshot != this.data){        this.snapshot.sort(direction, fn);    }},

4. 之所以进行分组之前首先按分组字段进行排序,个人臆断原因有二。

 A. 排序字段跟分组字段不同,即使排好序后,分组还是有可能打破排序的顺序的。

 B. 跟GroupingView的写法有关系,见下文。

5.GroupingView.js的doRender()源码(有删减):

doRender : function(cs, rs, ds, startRow, colCount, stripe){    var groups = [], curGroup, i, len, gid;        for(i = 0, len = rs.length; i < len; i++){            var rowIndex = startRow + i;            var r = rs[i],                gvalue = r.data[groupField],                g = this.getGroup(gvalue, r, rowIndex, colIndex, ds);            if(!curGroup || curGroup.group != g){ // 关键                curGroup = {                    group: g,                    gvalue: gvalue,                    groupId: gid,                    startRow: rowIndex,                    rs: [r]                };                groups.push(curGroup);            }else{                curGroup.rs.push(r);            }            r._groupId = gid;        }}

此方法就是构造分组列表,简单的说,他会循环GroupStore中的每个条目,判断如果groupField的值跟当前组的值相同,则把此条目放入当前分组;否则的话,新建一个分组。

他这么做,就是假设store是按照groupField进行了排序。从applySort()方法中,我们发现他会强制按groupField进行升序排序。这也正是导致最终视图的原因。

6.说些风凉话。在服务端排序在客户端分组,事件很不靠谱的事儿。Ext的处理方式就更不靠谱了(简单看了一下3.2中的处理就优雅多了)。

7. 折中的办法:按照某个字段分组,然后组内的条目按照某某字段分组。所以,干脆把排序和分组要么都放在服务器端,客户端不处理;要么都放在客户端,服务器端不干预。

8.我们采用排序和分组都在服务器端完成,有一定的局限性

var store = new Ext.data.GroupingStore({        reader: new BidResultItemXmlReader(),        url: Ipms.StateAssetOfficeService + '/QueryBidResultItem',        sortInfo: { field: 'id', direction: "DESC" },        remoteSort: true, // 配置1        remoteGroup: true,// 配置2        groupField: 'groupField'    });