前言
五一期間學習Ext很痛苦也很快樂,到現在也算是小有所成,陸陸續續的開始在專案中使用,Ext的表格據統計是使用率最高的一個元件,實在是很強大,但我以為關鍵是很漂亮,而他本身並不支援資料的統計功能,但是我們可以在他的sample裡面找到一個Live Group Summary的例子,但是這個例子僅能夠統計一頁是資料,實際使用中是不現實的,鼓搗2天后有了這個偏方 : ) 下面和大家一起分享。
版本
ext-3.0-rc1
正文
1. 截圖效果
2. 修改原始碼 ext-3.0-rc1\source\data\JsonReader.js,新增彙總接受資料的屬性,注意程式碼紅色部分。
2.1 新增屬性,this.dataSum = 0,原始碼97行後:
meta = meta || {};
this.dataSum = 0;//add
Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields);
};
2.1 為屬性賦值,原始碼180 行左右,紅色部分。
// over 2009-5-3
if(s.dataSum){
this.dataSum = o.dataSum;
}
if(s.totalProperty) {
this.getTotal = this.getJsonAccessor(s.totalProperty);
}
2. 實現統計功能的 GroupSummary.js,本程式碼來源於 http://extjs.com/forum/showthread.php?t=21331。這裡沒有用自帶例子裡面的GroupSummary.js,因為在我這邊報錯。
Ext.ux.grid.GridSummary = function(config) {
Ext.apply(this, config);
};
Ext.extend(Ext.ux.grid.GridSummary, Ext.util.Observable, {
init : function(grid) {
this.grid = grid;
this.cm = grid.getColumnModel();
this.view = grid.getView();
var v = this.view;
// override GridView's onLayout() method
v.onLayout = this.onLayout;
v.afterMethod('render', this.refreshSummary, this);
v.afterMethod('refresh', this.refreshSummary, this);
v.afterMethod('syncScroll', this.syncSummaryScroll, this);
v.afterMethod('onColumnWidthUpdated', this.doWidth, this);
v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);
// update summary row on store's add/remove/clear/update events
grid.store.on({
add: this.refreshSummary,
remove: this.refreshSummary,
clear: this.refreshSummary,
update: this.refreshSummary,
scope: this
});
if (!this.rowTpl) {
this.rowTpl = new Ext.Template(
'<div class="x-grid3-summary-row x-grid3-gridsummary-row-offset">',
'<table class="x-grid3-summary-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
'<tbody><tr>{cells}</tr></tbody>',
'</table>',
'</div>'
);
this.rowTpl.disableFormats = true;
}
this.rowTpl.compile();
if (!this.cellTpl) {
this.cellTpl = new Ext.Template(
'<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}">',
'<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>',
"</td>"
);
this.cellTpl.disableFormats = true;
}
this.cellTpl.compile();
},
calculate : function(rs, cm) {
var data = {}, cfg = cm.config;
for (var i = 0, len = cfg.length; i < len; i++) { // loop through all columns in ColumnModel
var cf = cfg[i], // get column's configuration
cname = cf.dataIndex; // get column dataIndex
// initialise grid summary row data for
// the current column being worked on
data[cname] = 0;
if (cf.summaryType) {
for (var j = 0, jlen = rs.length; j < jlen; j++) {
var r = rs[j]; // get a single Record
data[cname] = Ext.ux.grid.GridSummary.Calculations[cf.summaryType](r.get(cname), r, cname, data, j);
}
}
}
return data;
},
onLayout : function(vw, vh) {
if (Ext.type(vh) != 'number') { // handles grid's height:'auto' config
return;
}
// note: this method is scoped to the GridView
if (!this.grid.getGridEl().hasClass('x-grid-hide-gridsummary')) {
// readjust gridview's height only if grid summary row is visible
this.scroller.setHeight(vh - this.summary.getHeight());
}
},
syncSummaryScroll : function() {
var mb = this.view.scroller.dom;
this.view.summaryWrap.dom.scrollLeft = mb.scrollLeft;
this.view.summaryWrap.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
},
doWidth : function(col, w, tw) {
var s = this.view.summary.dom;
s.firstChild.style.width = tw;
s.firstChild.rows[0].childNodes[col].style.width = w;
},
doAllWidths : function(ws, tw) {
var s = this.view.summary.dom, wlen = ws.length;
s.firstChild.style.width = tw;
var cells = s.firstChild.rows[0].childNodes;
for (var j = 0; j < wlen; j++) {
cells[j].style.width = ws[j];
}
},
doHidden : function(col, hidden, tw) {
var s = this.view.summary.dom,
display = hidden ? 'none' : '';
s.firstChild.style.width = tw;
s.firstChild.rows[0].childNodes[col].style.display = display;
},
renderSummary : function(o, cs, cm) {
cs = cs || this.view.getColumnData();
var cfg = cm.config,
buf = [],
last = cs.length - 1;
for (var i = 0, len = cs.length; i < len; i++) {
var c = cs[i], cf = cfg[i], p = {};
p.id = c.id;
p.style = c.style;
p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
if (cf.summaryType || cf.summaryRenderer) {
p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o);
} else {
p.value = '';
}
//此處設定預設不顯示時用什麼符號標記
if (p.value == undefined || p.value === "") p.value = "-";
buf[buf.length] = this.cellTpl.apply(p);
}
return this.rowTpl.apply({
tstyle: 'width:' + this.view.getTotalWidth() + ';',
cells: buf.join('')
});
},
refreshSummary : function() {
var g = this.grid, ds = g.store,
cs = this.view.getColumnData(),
cm = this.cm,
rs = ds.getRange(),
data = this.calculate(rs, cm),
buf = this.renderSummary({data: data}, cs, cm);
if (!this.view.summaryWrap) {
this.view.summaryWrap = Ext.DomHelper.insertAfter(this.view.scroller, {
tag: 'div',
cls: 'x-grid3-gridsummary-row-inner'
}, true);
}
this.view.summary = this.view.summaryWrap.update(buf).first();
},
toggleSummary : function(visible) { // true to display summary row
var el = this.grid.getGridEl();
if (el) {
if (visible === undefined) {
visible = el.hasClass('x-grid-hide-gridsummary');
}
el[visible ? 'removeClass' : 'addClass']('x-grid-hide-gridsummary');
this.view.layout(); // readjust gridview height
}
},
getSummaryNode : function() {
return this.view.summary
}
});
Ext.reg('gridsummary', Ext.ux.grid.GridSummary);
/*
* all Calculation methods are called on each Record in the Store
* with the following 5 parameters:
*
* v - cell value
* record - reference to the current Record
* colName - column name (i.e. the ColumnModel's dataIndex)
* data - the cumulative data for the current column + summaryType up to the current Record
* rowIdx - current row index
*/
Ext.ux.grid.GridSummary.Calculations = {
sum : function(v, record, colName, data, rowIdx) {
return data[colName] + Ext.num(v, 0);
},
count : function(v, record, colName, data, rowIdx) {
return rowIdx + 1;
},
max : function(v, record, colName, data, rowIdx) {
return Math.max(Ext.num(v, 0), data[colName]);
},
min : function(v, record, colName, data, rowIdx) {
return Math.min(Ext.num(v, 0), data[colName]);
},
average : function(v, record, colName, data, rowIdx) {
var t = data[colName] + Ext.num(v, 0), count = record.store.getCount();
return rowIdx == count - 1 ? (t / count) : t;
}
}
3. 呼叫程式碼
3.1 改後的JsonReader呼叫方法:
totalProperty: 'count',
root: 'result',
dataSum: 'dataSum' //注意了,這個是我自定義的屬性(成員變數)
},[
{ name: 'fgsname' },
{ name: 'dianname'},
{ name: 'asd' },
{ name: 'Money',type: 'float'}
]);
3.2 為GridPanel新增外掛
var grid = new Ext.grid.GridPanel({
plugins: summary,
//
3.3 修改ColumnModel
return '合計:'+jr.dataSum;
}
var dataColumns = new Ext.grid.ColumnModel([
{header: "編 號", align:'center', dataIndex: 'asd'},
{header: "分公司", align:'center', dataIndex: 'fgsname',locked: true},
{header: "店 面", align:'center', dataIndex: 'dianname'},
{header: "餘 額", align:'center', dataIndex: 'Money',summaryRenderer:renderSummary}
]);
4. 程式碼下載:
更新:
1. 2009-5-6 請在我修改後的JsonReader.js大概210行左右加上如下標紅程式碼:
//add
if(s.dataSum){
this.dataSum = o.dataSum;
}
if(s.totalProperty){
var v = parseInt(this.getTotal(o), 10);
if(!isNaN(v)){
totalRecords = v;
}
}
2. 2009-5-13 如果在同一頁面不是通過重新整理來搜尋的,可能會出現沒有搜尋結果而表格的資料確沒有清掉統計也是上次搜尋的結果,需要在搜尋前加上如下三行程式碼就可以了:
jr.dataSum = 0;
summary.refreshSummary();
結束
開源專案這點還是非常好的,就是你看不順眼或者根據自己的需求可以任意的修改程式碼,但是修改的時候請小心一點,需要大致明白裡面的工作機制。