PDA

View Full Version : [OPEN] [OPEN-1490] Toggeling Grouping, bug? (GroupingStore, GroupingView & EditorGridPanel)



ReSpawNnL
7 Jan 2011, 4:53 AM
Hey guys,

I'm trying to toggle the grouping on a grid of mine, which, by all standards works fine.

I'm using this little piece of code to toggle it all.


if (summary.isGrouped()) {
store.clearGrouping();
} else {
store.groupBy('group', true);
}

Now, that doesn't work, because the custom (native Ext) "GroupSummary" and "HybridSummary" interfere with recalculating.

Where it all fails, is this function.


doHidden : function(col, hidden, tw) {
if(!this.isGrouped()){
return;
}
var gs = this.view.getGroups(),
len = gs.length,
i = 0,
s,
display = hidden ? 'none' : '';
for(; 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;
}
},

Why? Well, let me explain. I've narrowed it down to the "this.grid.getGroups()" and "isGrouped()" function. The "isGrouped()" function checks wether the 'groupField' in the store is set and isn't empty, like so:


isGrouped : function(){
return !Ext.isEmpty(this.grid.getStore().groupField);
},[PHP]

All well and good, since the "clearGrouping()" function from the GroupingStore sets it's internal this.groupField to false. Now, !Ext.isEmpty shouldn't pass that, which it doesn't.

[PHP]clearGrouping : function(){
this.groupField = false;

if(this.remoteGroup){
if(this.baseParams){
delete this.baseParams.groupBy;
delete this.baseParams.groupDir;
}
var lo = this.lastOptions;
if(lo && lo.params){
delete lo.params.groupBy;
delete lo.params.groupDir;
}

this.reload();
}else{
this.sort();
this.fireEvent('datachanged', this);
}
},

As you can see, it set's it to false and in my case, only performs the "sort()" function and then finishes up with a event firing. Perfect if you ask me.

When I use the "groupBy()" function, I am not sure anymore what it does exactly. All I know for now is that it ends up in the native addon "GroupingSummary", where the "doHidden()" function is executed, followed by "doAllWidths()". Both functions have the same calculation thus both fail. Why? Ah, yes;

Both functions fetch the groups from the GroupingView via "this.view.getGroups()". Well, if I am TOGGELING these groups, there WOULDN'T BE ANY GROUPS. So, why does it even try to attempt it? Am I missing a step or is this piece of code just bugged?

Please help me out here and thanks in advance!

Condor
7 Jan 2011, 5:10 AM
"Both functions have the same calculation thus both fail"... Fail how?

Both methods check isGrouped first, so they shouldn't execute when the grid is not grouped.

ReSpawNnL
7 Jan 2011, 5:12 AM
That's the weird thing. Before I try the "groupBy()" function, I console log the state of the "isGrouped()" function, which is clearly false. It still continues on.

/edit

From the Firebug console:


State: true State: false

s is undefined: (s.style.width = tw;)


console.log(summary.isGrouped());

if (summary.isGrouped()) {
store.clearGrouping();
} else {
store.groupBy('group', true, 'ASC');
}

Condor
7 Jan 2011, 5:39 AM
Ext.isEmpty(false) returns false, so it indeed doesn't work.

IMHO it should simply be using:

Ext.override(Ext.ux.grid.GroupSummary, {
isGrouped : function(){
return this.grid.getStore().getGroupState();
}
});

ReSpawNnL
7 Jan 2011, 5:40 AM
Indeed. We'll, I can always jerryrig the function but still, calculating the with function ("doHidden()") doesn't work. This is because it tries to get grid.getGroups() when there aren't any. Is this function bugged or?

Condor
7 Jan 2011, 5:56 AM
You posted a complete analysis, but you still didn't tell me what the actually problem is.

Do you get a javascript error somewhere (details please) or does it just not display what you want it to?

ReSpawNnL
7 Jan 2011, 6:03 AM
I did. :) See post #3 (http://www.sencha.com/forum/showthread.php?120587-Toggeling-Grouping-bug-(GroupingStore-GroupingView-amp-EditorGridPanel)&p=558497&posted=1#post558462).

No matter, the real problem is, I cannot toggle between grouped headers and ungrouped headers. Clearing the groups works like a charm and futher sorting isn't a problem. Now, when I try to re'group' the grid, it fails due to measuring the widths of the groups, when the groups aren't yet built.

Condor
7 Jan 2011, 6:43 AM
Don't understand, getGroups should only return an non-empty array when the groups are actually there. Will need to debug...

I'll move this thread to the Bugs section.

Could you provide the other relevant bug information (Ext version etc.)?

ReSpawNnL
7 Jan 2011, 7:13 AM
Sounds like a plan.

I'm using ExtJS 3.3.1, indicated by the following header.

/*
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/However, I am using the -debug.js file (without comments). I assume that's the same.

Now, keep in mind that the following is slimmed down quite a bit, because most of it is closed source with some complex calculations and so forth, but those are not connected to the grouping errors.


// The following GroupingStore is called via a cached storage (custom made)
// this.get('DebtorInvoices', 'store', config)
return new Ext.data.GroupingStore({
storeId: 'actx-store-debtorinvoices-acc'+config.id,
autoSave: false,
baseParams: {
action: 'read/debtor/invoice',
accountId: config.id,
ctx: 'web',
HTTP_MODAUTH: this.cfg('auth')
},
paramNames: {
start: 'start',
limit: 'limit',
sort: 'sort',
dir: 'dir'
},
reader: new Ext.data.JsonReader({
root: 'data',
idProperty: 'id',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message',
fields: [
'id', 'group', 'description', 'articleid', 'articlecode', 'quantity', 'unit', 'unitprice', 'discountpercent', 'discountvaluta', 'tax'
/*{name: 'id', type: 'int'},
{name: 'group', type: 'string'},
{name: 'description', type: 'string'},
{name: 'articleid', type: 'int'},
{name: 'articlecode', type: 'int'},
{name: 'quantity', type: 'int'},
{name: 'unit', type: 'int'},
{name: 'unitprice', type: 'float'},
{name: 'discountpercent', type: 'float'},
{name: 'discountvaluta', type: 'float'},
{name: 'tax', type: 'float'}*/
]
}),
proxy: new Ext.data.HttpProxy({
url: this.cfg('structure').connector
}),
writer: new Ext.data.JsonWriter({
encode: true,
writeAllFields: false
}),
sortInfo: {
field: 'group',
direction: 'ASC'
},
groupField: 'group'
});

var summary = new Ext.ux.grid.HybridSummary();

new Ext.grid.EditorGridPanel({
id: (config.args.action == 'new') ? 'actx-grid-invoicegridnew-acc'+config.id : 'actx-grid-invoicegridedit-acc'+config.id,
ds: this.get('DebtorInvoices', 'store', config),
columns: [{
header: 'Artikel',
width: 35,
sortable: true,
dataIndex: 'articleid',
hideable: true,
editor: new Ext.form.TextField({
allowBlank: false
})
}, {
header: 'Artikelcode',
width: 10,
sortable: true,
dataIndex: 'articlecode',
hideable: true,
editor: new Ext.form.TextField({
allowBlank: false
})
}, {
header: 'Productgroep',
width: 10,
sortable: true,
dataIndex: 'group',
hideable: true,
hidden: true
},{
header: 'Omschrijving',
width: 55,
sortable: true,
dataIndex: 'description'
}],
view: new Ext.grid.GroupingView({
//forceFit: true,
showGroupName: true,
enableNoGroups: true,
enableGroupingMenu: true,
hideGroupedColumn: true,
autoFill: true
}),
plugins: [summary],
tbar: [{
text: 'Nieuwe regel',
icon: this.icon('add'),
scope: this,
handler: function(grid) {
var store = this.get('DebtorInvoices', 'store', config);
var ids = store.collect('id');

var Record = Ext.data.Record.create(store.fields.items);

store.add(new Record({
id: (ids.length + 1),
group: 'Factuur '+(ids.length + 1),
description: '',
articleid: 0,
articlecode: 0,
quantity: 0,
unit: 0,
unitprice: 0,
discountpercent: 0,
discountvaluta: 0,
tax: 0
}));
}
}, '->', {
text: 'Subtotalen',
icon: this.icon('sum'),
handler: function() {
summary.toggleSummaries();
}
}, {
text: 'Groeperen',
icon: this.icon('group'),
scope: this,
handler: function() {
// This is where all the crazyness starts! :)
var store = this.get('DebtorInvoices', 'store', config);
console.log(summary.isGrouped());

if (summary.isGrouped()) {
store.clearGrouping();
} else {
store.groupField = 'group';
store.groupBy('group', true, 'ASC');
}
}
}],
autoHeight: true,
clicksToEdit: 1,
trackMouseOver: false
});I'm also using the provided groupsummary.ext.txt. From there you can see where I got it all.

Now, that example is also documented and can be found in the examples, where I got it from. I customized it quite a bit, but the basic functionality remains intact.

As for now, the grid is loaded with no records and via a button records can be added.

Now, the above presented example produces no errors, because it console.log's true every time, because !Ext.isEmpty renders (bool)false as (bool)true.

The beneath example causes a correct behaviour, but still doesn't renders groups and produces the before mentioned error.


var store = this.get('DebtorInvoices', 'store', config);
console.log(summary.isGrouped());

if (summary.isGrouped()) {
store.clearGrouping();
store.groupField = '';
} else {
store.groupField = 'group';
store.groupBy('group', true, 'ASC');
}And thus the error:


true
false
s is undefined
[Decompile this error] s.style.width = tw;
on line 1999 of extensions.jsline 1999 of extensions.js represents this chunk of code:


doHidden : function(col, hidden, tw){
if(!this.isGrouped()){
return;
}
var gs = this.view.getGroups(),
len = gs.length,
i = 0,
s,
display = hidden ? 'none' : '';
for(; i < len; i++){
s = gs[i].childNodes[2];
s.style.width = tw; // Line 1999
s.firstChild.style.width = tw;
s.firstChild.rows[0].childNodes[col].style.display = display;
}
},/edit

Oh yea, as mentioned before "this.view.getGroups()" is empty the first time (after the clearGrouping). The second time (which is correct), it contains 4 groups and thus the length is 4. Only it fails the very first time, so that would indicate that s could not be retrieved from gs[i].

/edit

Further deconstruction indicates that the array is filled with a single dimensioned ARRAY. Logging provides the following:

[div.x-grid3-row, div.x-grid3-row, div.x-grid3-row, div.x-grid3-row, div.x-grid3-row, div.x-grid3-row] So what business has childNodes[2] to do with this all?