我们知道,实现extjs的Grid必须先定义一个ColumnModel,指定列名称、列标题、宽度、对齐方式,然后定义一个Record和Store,指定数据源的字段名、类型,最后定义一个Grid,完整过程的代码类似如下:
// dataIndex maps the column to the specific data field in
// the data store (created below)
var cmCust = new Ext.grid.ColumnModel([{
header: " 客户编码 " ,
dataIndex: ' CUSTID ' ,
width: 70
}, {
header: " 客户简称 " ,
dataIndex: ' CUSTSHORTNAME ' ,
width: 200
}, {
header: " 预收金额 " ,
dataIndex: ' PREPAYMENT ' ,
width: 100 ,
align: ' right ' ,
renderer: Ext.util.Format.gbMoney
},{
header: " 应收金额 " ,
dataIndex: ' PAYMENT ' ,
width: 100 ,
align: ' right ' ,
renderer: Ext.util.Format.gbMoney
},{
header: " 实际欠款 " ,
dataIndex: ' SJQK ' ,
width: 100 ,
align: ' right ' ,
renderer: Ext.util.Format.gbMoney
},{
header: " 信用期限 " ,
dataIndex: ' LICENSEPERIOD ' ,
width: 100 ,
align: ' right '
},{
header: " 信用额度 " ,
dataIndex: ' LICENSEMONEY ' ,
width: 100 ,
align: ' right ' ,
renderer: Ext.util.Format.gbMoney
}]);
// by default columns are sortable
cmCust.defaultSortable = true ;
// this could be inline, but we want to define the order record
// type so we can add records dynamically
var cust = Ext.data.Record.create([
{name: ' CUSTID ' , type: ' string ' },
{name: ' CUSTSHORTNAME ' , type: ' string ' },
{name: ' PREPAYMENT ' , type: ' float ' },
{name: ' PAYMENT ' , type: ' float ' },
{name: ' SJQK ' , type: ' float ' },
{name: ' LICENSEPERIOD ' , type: ' float ' },
{name: ' LICENSEMONEY ' , type: ' float ' }
]);
// create the Data Store
var dsCust = new Ext.data.Store({
// load using HTTP
proxy: new Ext.data.HttpProxy({url: ' ../getCustList.do ' }),
// the return will be XML, so lets set up a reader
reader: new Ext.data.DynamicXmlReader({
// records will have a "customer" tag
record: ' table ' ,
totalRecords: ' records '
}, cust)
});
var gridCust = new Ext.grid.DynamicGrid( ' customer-grid ' , {
ds: dsCust,
cm: cmCust,
selModel: new Ext.grid.RowSelectionModel(),
enableColLock: false ,
loadMask: true , });
gridCust.render();
此过程相当繁琐。很多情况下,我们需要一个通用的动态Grid,不必指定字段名、字段类型、列头等信息,而是根据返回记录(通常是json或xml格式)的结构和内容,自动将记录展现在Grid中,这就是Dynamic Grid。
extjs的论坛上有两种方式实现Dynamic Grid,一种是json,另一种是xml。前者请看http://extjs.com/learn/Ext_Extensions。对于xml方式,需要扩展Ext.data.XmlReader和Ext.grid.Grid,具体根据返回的xml的结构,假设返回的xml类似:
< response success ='true'>
<database >
< record >
< SUPPLIERID > <![CDATA[ 1 ]]> </ SUPPLIERID >
< SUPPLIERSHORTNAME > <![CDATA[ 中原公司 ]]> </ SUPPLIERSHORTNAME >
< PREPAYMENT > <![CDATA[ 0.00000000 ]]> </ PREPAYMENT >
< PAYMENT > <![CDATA[ 0.00000000 ]]> </ PAYMENT >
< SJQK > <![CDATA[ 0.00000000 ]]> </ SJQK >
</ record >
< record >
< SUPPLIERID > <![CDATA[ 2 ]]> </ SUPPLIERID >
< SUPPLIERSHORTNAME > <![CDATA[ 广州市五金公司 ]]> </ SUPPLIERSHORTNAME >
< PREPAYMENT > <![CDATA[ 0.00000000 ]]> </ PREPAYMENT >
< PAYMENT > <![CDATA[ 6855.00000000 ]]> </ PAYMENT >
< SJQK > <![CDATA[ 6855.00000000 ]]> </ SJQK >
</ record >
</ database >
</ response >
在上面的xml内容中,每个<record>是一个记录,我们必须得到<record>中所有子元素的名称,做为Grid的列标题:
var cols = [];
var recordType = store.reader.recordType;
var fields = recordType.prototype.fields;
for ( var i = 0 ; i < fields.keys.length; i ++ ) {
var fieldName = fields.keys[i];
var field = recordType.getField(fieldName);
cols[i] = {
header: field.header,
dataIndex: field.name,
tooltip: field.tooltip,
hidden: field.hidden,
renderer: eval(field.renderer)
};
}
Ext.grid.DynamicColumnModel.superclass.constructor.call( this , cols);
};
Ext.extend(Ext.grid.DynamicColumnModel, Ext.grid.ColumnModel, {});
Ext.data.DynamicXmlReader = function (config) {
Ext.data.DynamicXmlReader.superclass.constructor.call( this , config, []);
};
Ext.extend(Ext.data.DynamicXmlReader, Ext.data.XmlReader, {
getRecordType : function (data) {
recordDefinition = Ext.DomQuery.select( this.meta.record + ':first-child > *', data);
var arr = [];
for ( var i = 0 ; i < recordDefinition.length; i ++ ) {
arr[i] = {
name:recordDefinition[i].tagName,
header:recordDefinition[i].tagName
};
}
this .recordType = Ext.data.Record.create(arr);
return this .recordType;
},
readRecords : function (doc) {
this .xmlData = doc;
var root = doc.documentElement || doc;
this .getRecordType(root);
return Ext.data.DynamicXmlReader.superclass.readRecords.call( this , doc);
}
});
Ext.grid.GridView.prototype.bindColumnModel = function (cm) {
if ( this .cm){
this .cm.un( " widthchange " , this .updateColumns, this );
this .cm.un( " headerchange " , this .updateHeaders, this );
this .cm.un( " hiddenchange " , this .handleHiddenChange, this );
this .cm.un( " columnmoved " , this .handleColumnMove, this );
this .cm.un( " columnlockchange " , this .handleLockChange, this );
}
if (cm){
this .generateRules(cm);
cm.on( " widthchange " , this .updateColumns, this );
cm.on( " headerchange " , this .updateHeaders, this );
cm.on( " hiddenchange " , this .handleHiddenChange, this );
cm.on( " columnmoved " , this .handleColumnMove, this );
cm.on( " columnlockchange " , this .handleLockChange, this );
}
this .cm = cm;
};
Ext.grid.DynamicGrid = function (container, config) {
Ext.grid.DynamicGrid.superclass.constructor.call( this , container, config);
};
Ext.extend(Ext.grid.DynamicGrid, Ext.grid.Grid, {
render : function () {
this .dataSource.addListener( ' load ' , this .doReconfiguration, this );
this .colModel = new Ext.grid.DefaultColumnModel([{ header: '' , dataIndex: '' }]);
Ext.grid.DynamicGrid.superclass.render.call( this );
},
doReconfiguration : function () {
this .colModel = new Ext.grid.DynamicColumnModel( this .dataSource);
this .view.bindColumnModel( this .colModel);
this .view.refresh( true );
// this.dataSource.removeListener("load", this.doReconfiguration);
}
});
上面的代码实现了DynamicColumnModel、DynamicXmlReader和DynamicGrid,DynamicXmlReader根据xml文件的结构和内容,自动配置一个ColumnModel和Store,这样最终的Dynamic Grid实现代码如下所示:
// load using HTTP
proxy: new Ext.data.HttpProxy({url: ' ../getCustList.do ' }),
// the return will be XML, so lets set up a reader
reader: new Ext.data.DynamicXmlReader({
record: ' record ' ,
totalRecords: ' records '
})
});
var gridCust = new Ext.grid.DynamicGrid( ' customer-grid ' , {
ds: dsCust,
// cm: cmCust,
selModel: new Ext.grid.RowSelectionModel(),
enableColLock: false ,
loadMask: true
});
gridCust.render();
相比本文开头的代码简化了很多。当然还有很多地方需要优化,例如实现描述性的列标题(而不是以字段名做为列标题),配置列宽和对齐方式,实现Dynamic EditorGrid等,通常我们还需要一个配置档,将这些原先硬编码的信息在配置档里配置好,然后在返回的json和xml中,除了有结果记录外,还有配置档中的meta信息,以便根据这些信息自动展现Dyanmic Grid。
相比而言,由于json较xml简洁,而且JsonReader本身就支持meta数据,使用JsonReader实现DynamicGrid较XmlReader方式简单,运行效率也高。当然,前提是必须将记录转换成json格式,目前json格式可能不如xml格式使用的多。