實現extjs的Dynamic Grid

我們知道,實現extjs的Grid必須先定義一個ColumnModel,指定列名稱、列標題、寬度、對齊方式,然後定義一個Record和Store,指定數據源的字段名、類型,最後定義一個Grid,完整過程的代碼類似如下:
    // the column model has information about grid columns
    // 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類似:

<?xml version="1.0" encoding="UTF-8"?>
<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的列標題:

Ext.grid.DynamicColumnModel = function(store) {
    
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實現代碼如下所示:

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({
               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格式使用的多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章