PDA

View Full Version : Grid Summary Plugin



cutigersfan
13 Dec 2007, 3:52 PM
I needed a way to add a summary row to a grid. This is similar to (and adapted from) the GroupSummary from the samples. Here are the situations when this might be useful:
Table summary needed, but not using grouping.
Not using paging (entire table shown)This plugin seems to work fine for me. If anyone has ways to improve or make it more efficient, then please speak up.
Use the same css styles from the sample:

.x-grid3-summary-row {background:#F1F2F4 none repeat scroll 0%;color:#333333;border:1px solid #ededed;border-top-color:#fff;}
.x-grid3-summary-row .x-grid3-cell-inner {font-weight:bold;padding-bottom:4px;}
.x-grid3-cell-first .x-grid3-cell-inner {padding-left:16px;}
.x-grid-hide-summary .x-grid3-summary-row {display:none;}
.x-grid3-summary-msg {font-weight:bold;padding:4px 16px;}
the plugin code:

Ext.grid.GridSummary = function(config){
Ext.apply(this, config);
};

Ext.extend(Ext.grid.GridSummary, Ext.util.Observable, {
init : function(grid){
this.grid = grid;
this.cm = grid.getColumnModel();
this.view = grid.getView();
this.beforeInsert = false;

var v = this.view;
this.doRenderBase = v.doRender;
v.doRender = this.doRender.createDelegate(this);

v.beforeMethod('insertRows',this.doBeforeInsert,this);
v.afterMethod('onColumnWidthUpdated', this.doWidth, this);
v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);
v.afterMethod('onUpdate', this.doUpdate, this);
v.afterMethod('onRemove', this.doRemove, this);

if(!this.rowTpl){
this.rowTpl = new Ext.Template(
'<div class="x-grid3-summary-row" style="{tstyle}">',
'<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">{value}</div>',
"</td>"
);
this.cellTpl.disableFormats = true;
}
this.cellTpl.compile();
},

toggleSummaries : function(visible){
var el = this.grid.getGridEl();
if(el){
if(visible === undefined){
visible = el.hasClass('x-grid-hide-summary');
}
el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary');
}
},

renderSummary : function(o, cs){
cs = cs || this.view.getColumnData();
var cfg = this.cm.config;

var buf = [], c, p = {}, cf, last = cs.length-1;
for(var i = 0, len = cs.length; i < len; i++){
c = cs[i];
cf = cfg[i];
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 = "&#160;";
buf[buf.length] = this.cellTpl.apply(p);
}

return this.rowTpl.apply({
tstyle: 'width:'+this.view.getTotalWidth()+';',
cells: buf.join('')
});
},

calculate : function(rs, cs){
var data = {}, r, c, cfg = this.cm.config, cf;
for(var j = 0, jlen = rs.length; j < jlen; j++){
r = rs[j];
for(var i = 0, len = cs.length; i < len; i++){
c = cs[i];
cf = cfg[i];
if(cf.summaryType){
data[c.name] = Ext.grid.GridSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data);
}
}
}
return data;
},

doRender : function(cs, rs, ds, startRow, colCount, stripe){
var buf = this.doRenderBase.call(this.view,cs, rs, ds, startRow, colCount, stripe);
// We normally don't want to add summary row to every insert.
// However, we do need to if this is the first row
if (!this.beforeInsert || this.view.getRows().length==0){
var data = this.calculate(rs, cs);
buf += this.renderSummary({data: data}, cs);
} else {
this.refreshSummary();
}
this.beforeInsert = false;
return buf;
},

doWidth : function(col, w, tw){
var gs = this.view.getRows(), s;
if (gs.length > 0){
s = gs[gs.length - 1];
s.style.width = tw;
s.firstChild.style.width = tw;
s.firstChild.rows[0].childNodes[col].style.width = w;
}
},

doAllWidths : function(ws, tw){
var gs = this.view.getRows(), s, cells, wlen = ws.length;
if (gs.length > 0) {
s = gs[gs.length - 1];
s.style.width = tw;
s.firstChild.style.width = tw;
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 gs = this.view.getRows(), s, display = hidden ? 'none' : '';
for(var i = 0, len = gs.length; i < len; i++){
s = gs[i].childNodes[2];
s.style.width = tw;
s.firstChild.style.width = tw;
s.firstChild.rows[0].childNodes[col].style.display = display;
}
},

getSummaryNode : function(){
return this.view.el.child('.x-grid3-summary-row');
},

refreshSummary : function(){
var rs = [];
this.grid.store.each(function(r){
rs[rs.length] = r;
});
var cs = this.view.getColumnData();
var data = this.calculate(rs, cs);
var markup = this.renderSummary({data: data}, cs);
var body = this.view.el.child('.x-grid3-body').dom;

var existing = this.getSummaryNode();
if(existing){
body.removeChild(existing.dom);
}
Ext.DomHelper.append(body, markup);
return true;
},

removeSummary : function(){
var existing = this.getSummaryNode();
if (existing) {
var body = this.view.el.child('.x-grid3-body').dom;
body.removeChild(existing.dom);
}
},

doUpdate : function(ds, record){
this.refreshSummary();
},

doRemove : function(ds, record, index, isUpdate){
if(!isUpdate){
if (ds.getCount() === 0) this.removeSummary();
else this.refreshSummary();
}
},

doBeforeInsert : function(){
this.beforeInsert = true;
}
});

Ext.grid.GridSummary.Calculations = {
'sum' : function(v, record, field){
return v + (record.data[field]||0);
},

'count' : function(v, record, field, data){
return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
},

'max' : function(v, record, field, data){
var v = record.data[field];
var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max'];
return v > max ? (data[field+'max'] = v) : max;
},

'min' : function(v, record, field, data){
var v = record.data[field];
var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min'];
return v < min ? (data[field+'min'] = v) : min;
},

'average' : function(v, record, field, data){
var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0)));
return t === 0 ? 0 : t / c;
}
}

soreport
13 Dec 2007, 4:10 PM
good,it seems very nice!!!

soreport
13 Dec 2007, 5:05 PM
if the summary row can be fixed to bottom,that will be perfect!!

cutigersfan
14 Dec 2007, 9:40 AM
The summary row should be on the bottom.

JeffG
19 Dec 2007, 12:03 PM
Just a note, if the grid becomes grouped, I get JS errors. Do you want me to post or is it not expected to work when grouped?

tinker
20 Dec 2007, 1:44 AM
Hey! Good Work!

I guess I looked at it late or maybe could not wait for someone to make this plugin!!! :))

I noticed that readers have requested for the summary row to be fixed - I had my own version of GridSummary that has this feature... just thought it my be helpful.

Check it out here (http://extjs.com/forum/showthread.php?t=21331)

Happy Scripting!

galdaka
20 Dec 2007, 1:58 AM
Live example for testing?

Thanks in advance,

cutigersfan
20 Dec 2007, 3:55 AM
Just a note, if the grid becomes grouped, I get JS errors. Do you want me to post or is it not expected to work when grouped?


No, I stated in my original post that I didn't intend for this to be used when grouping is desired. It probably won't work in that situation. I didn't need grouping for my purposes.

cutigersfan
20 Dec 2007, 12:01 PM
Hey! Good Work!

I guess I looked at it late or maybe could not wait for someone to make this plugin!!! :))

I noticed that readers have requested for the summary row to be fixed - I had my own version of GridSummary that has this feature... just thought it my be helpful.

Check it out here (http://extjs.com/forum/showthread.php?t=21331)

Happy Scripting!


I tried your version and it seems to work the same as mine. I have made a update or two since original posting. I wasn't able to test grouping as it wasn't in my original design.

piskui07
21 Dec 2007, 7:16 AM
It seems nice... but... can you post some screenshot or... (best) a live example or ready_to_use_example zip?

Thanks in advance.
Bye

Ccomics88
18 Nov 2009, 11:33 AM
This plugin basically provides the functionality I need, only I do need it to work with grouping and group summaries. I know that you said that the summary row isn't supported with grouping, but, from a strict "expected functionality" standpoint, there really shouldn't be a summary row for the grouping menu.

So what I'd like to do is use this plugin, and when grouping is enabled, simply disable the summary row. That way there's no worry about trying to compute from stuff that's grouped. It seems like a simple enough problem.

I tried some things but haven't solved the problem yet. Here is one approach I tried that sort of works, but leads to problems.


doRender : function(cs, rs, ds, startRow, colCount, stripe){
var buf = this.doRenderBase.call(this.view,cs, rs, ds, startRow, colCount, stripe);
// We normally don't want to add summary row to every insert.
// However, we do need to if this is the first row
if(!this.view.enableGrouping){
if (this.beforeInsert || this.view.getRows().length==0){
var data = this.calculate(rs, cs);
buf += this.renderSummary({data: data}, cs);
} else {
this.refreshSummary();
}
this.beforeInsert = false;
}
return buf;
},

Could anyone point me in the right direction? Thanks.

velocat
15 May 2010, 8:32 PM
How I can make average without fields == 0 ?

aymanadou
23 Dec 2010, 1:48 AM
Salamou 3alaykom :)
Hi every body , i wanna thank all of you cause it really helpful, i'm using this plugin with 3.3 extjs and it still working good,
in fact as a personalized need i wanna do a distinct count,means we should return the number of different objects in this column of the grid.
Here is my approach, it 's simple but so helpful ,enjoy ;)

add this code in your "GridSummury.js" in Ext.grid.GridSummary.Calculations{}



var tmp="";
'distcount' : function(v, record, field, data){

if(tmp!=record.data[field])
{
data[field+'distcount'] ? ++data[field+'distcount'] : (data[field+'distcount'] = 1);
tmp=record.data[field];

}
return data[field+'distcount'];
},

Ps : To make this works good you should verify that the field you want to count is sorted. hope is helpful.