PDA

View Full Version : Multiple level of grouping in grids



Pages : [1] 2

venky0589
28 Jul 2008, 1:42 AM
Hi

Hi,
I implemented a multi level grouping in grids. This is my first posting, any feed back will help me improve the grouping grid

thanks

tchitani
28 Jul 2008, 9:21 PM
Hi

Great plugin.

However if I use it with JSON data from server, sorting does not work.

Thanks
Nik

galdaka
29 Jul 2008, 12:30 AM
Hi,


Excellent screenshot!! but the example not works for me (IE6). Can you post a example following the Ext examples structure folders?

Thanks in advance,

tchitani
29 Jul 2008, 2:23 AM
Hi

I was able to run the attached example on IE.
Just a hint: remove a paging toolbar (irrelevant to the array reader demo), remove rendering at the end and get rid of a couple of extra commas in JS file.

Regards
Nik

venky0589
29 Jul 2008, 4:34 AM
Hi
See a updated screen shot code , sorting , and store configured to JSON reader


thanks

tchitani
29 Jul 2008, 4:55 AM
Thank you for the JSON example. Works in IE/Mozilla.
Will be great to have a config option available: hideGroupedColumn: true
Will be also great to dynamically add/remove grouping columns.

galdaka
29 Jul 2008, 9:48 AM
Hi

Hi,
I implemented a multi level grouping in grids. This is my first posting, any feed back will help me improve the grouping grid

thanks

Two things:

1) Not works in IE6. But works fine in FF2!!.

2) Is posible add extra CSS for remove / customize extra lines in categorized rows?


I think this way is the best / easy solution for trasform a grid in a treegrid!!!

I upload the fixed version of "MultiGroup.html" for extract in "ext-2.1\examples\sourceMg" and run!!

Thanks in advance,

venky0589
30 Jul 2008, 3:53 AM
Hi
a update with Multi Grouping in grid with json ,separate css hidegroupcolumn property and sorting

galdaka
30 Jul 2008, 6:57 AM
Hi,


Is posible a original local demo for test pourposes?


Thanks in advance,

venky0589
30 Jul 2008, 10:29 PM
Hi

how can we implement drag drop for multi level grouping like in the screen shot

Thanks in advance

tchitani
30 Jul 2008, 11:52 PM
http://extjs.com/forum/showthread.php?t=36881&highlight=drag+drop+grid+column - something like that?

galdaka
31 Jul 2008, 12:48 AM
Animal have your solution...

http://www.extjs.com/forum/showthread.php?p=169004#post169004

Screenshot: http://s131.photobucket.com/player.swf?file=http://vid131.photobucket.com/albums/p286/TimeTrialAnimal/TreeGrid-1.flv&fs=1&os=1&ap=1

P.D: Local demo working on IE6?


Thanks in advance,

venky0589
31 Jul 2008, 1:18 AM
Hi
yes i know of that , but i could not get src for that , probably his employer did not want it to be released to the community. for this reason i added multi level grouping feature to grid

venky0589
4 Aug 2008, 4:54 AM
Hi

Continuing the Multi level grouping , i have implemented drag and drop from Tbar, will appreciate if some one can make it work on IE

Thanks

galdaka
4 Aug 2008, 9:45 AM
Hi

Continuing the Multi level grouping , i have implemented drag and drop from Tbar, will appreciate if some one can make it work on IE

Thanks

Your example not work in local
url: 'http://196.0.0.14:8080/EXTJS/documents.jsp',

Please post a example with correct references to a ext frameWork (Simply drag and drop to examples folder and run).

Thanks again,

venky0589
4 Aug 2008, 11:38 PM
Your example not work in local
url: 'http://196.0.0.14:8080/EXTJS/documents.jsp',Please post a example with correct references to a ext frameWork (Simply drag and drop to examples folder and run).

Thanks again,


change or modify to your JSON reader in Multi.js file

bvutukur
5 Aug 2008, 12:35 AM
Hi
a update with Multi Grouping in grid with json ,separate css hidegroupcolumn property and sorting

hi venky,

i was unable to download the zip file

galdaka
5 Aug 2008, 3:49 AM
change or modify to your JSON reader in Multi.js file

I think that You should make things easier to make more agile all of help process.

I have not any server instaled for test. Is posible a Local example?

Thanks in advance,

galdaka
5 Aug 2008, 4:07 AM
hi venky,

i was unable to download the zip file

All files in this forum are re-compressed.

1) Extract.

2) Rename to .zip

3) Extract again.


I hope help you,

mystix
5 Aug 2008, 5:53 AM
All files in this forum are re-compressed.

1) Extract.

2) Rename to .zip

3) Extract again.


I hope help you,
or simply download with Firefox. works all the time.

venky0589
5 Aug 2008, 11:02 PM
I think that You should make things easier to make more agile all of help process.

I have not any server instaled for test. Is posible a Local example?

Thanks in advance,

Replace the file Multi.js in the previous zip folder for example to work locally

galdaka
6 Aug 2008, 4:09 AM
Hi,

Thanks venky0589!!! =D> =D> =D>

Is a excellent start for make Treegrid

bvutukur
7 Aug 2008, 5:00 AM
hi galdaka,

the multigrouping is working fine for the example given by you.

i created multi_new.js to add my own column's. but when i am trying to drag any one of the column i am getting a script error saying 'this.fields' is null or not an object.

can you help me to resolve this issue. i am attaching the multi_new.js that i am using.

how to make the columns editable?

Thanks in Advance

ut_paule
7 Aug 2008, 9:35 AM
I spent a day looking for this, and what you posted in #14 seems to be the best thing i could find (Unless Animal released his version somewhere).

I have just spent a day hacking this around to do the following things

work on IE (i use v6)
to use the column headers, not the dataIndex names in the Group Text and on the toolbar (This was tricky as the dataIndex name was used internally in many places)
to make sure all groups had "rs" set (not just the final group) so i could see at the higher levels total record counts
I tried to indent the row so it was nested under groups, so it all still looks indented, this kind of works on FF, but not on IE (i am adding a margin-left on the x-grid3-row and header). I think this also screws up the basic sizing in ExtJS, like auto width etc, so i probably need a better way to do this
It seemed like getRows() is called many times and is an expensive routine, so i added in a cache for this - i welcome feedback as to whether this is a good idea
I also created a MultiGroupingPanel, to try and hide all the dropdown/toolbar stuff, i did notice in the process that there are some hardcoded things that probably need to be addressed to make this a true panel, where you can have more that one on the page (for example lines like clone.id = Ext.id('ven'); concern me.


You will see in the attached example huge amounts of firebug debugging, and i will continue to work on this some more, and try and gauge any feed back from others trying to sort this out.

One issue i have, as this is my first exposure to the DD stuff, is that when you drag a column to the toolbar, and in the process the "blue arrows" for moving the column appear they still stay there after the drag event has finished.

My intent is to have a final working version within an week or so, it will be under an LGPL and be part of the JaffaRIA module under the jaffa.sf.net (That is where my team are sticking all our ExtJS extensions and DWR intergration)

Future things i want to do to it are

make sure it works with the filter plug-in (how can you filter on a grouped column if it has been hidden) should there be a dropdown against the column name in the toolbar too?)
get it working with some kind of paging store
integrate the store with DWR (as that is what my project uses to access the DB)
support some kind of Export to Excel...
get the groupTpl so that can do totaling of other columns, beyond the simple rs.length counting
like Animals demo drag and drop to re-order groups would be nice
full state management intergration so it remembers what you were grouping by last time

galdaka
7 Aug 2008, 9:58 AM
ut_paule live example here:

http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

Thanks ut_paule. Great work!!!!

P.D: Awesome screenshot in FF2!!!!!!

venky0589
7 Aug 2008, 10:59 PM
I spent a day looking for this, and what you posted in #14 seems to be the best thing i could find (Unless Animal released his version somewhere).

I have just spent a day hacking this around to do the following things
work on IE (i use v6)
to use the column headers, not the dataIndex names in the Group Text and on the toolbar (This was tricky as the dataIndex name was used internally in many places)
to make sure all groups had "rs" set (not just the final group) so i could see at the higher levels total record counts
I tried to indent the row so it was nested under groups, so it all still looks indented, this kind of works on FF, but not on IE (i am adding a margin-left on the x-grid3-row and header). I think this also screws up the basic sizing in ExtJS, like auto width etc, so i probably need a better way to do this
It seemed like getRows() is called many times and is an expensive routine, so i added in a cache for this - i welcome feedback as to whether this is a good idea
I also created a MultiGroupingPanel, to try and hide all the dropdown/toolbar stuff, i did notice in the process that there are some hardcoded things that probably need to be addressed to make this a true panel, where you can have more that one on the page (for example lines like clone.id = Ext.id('ven'); concern me.
You will see in the attached example huge amounts of firebug debugging, and i will continue to work on this some more, and try and gauge any feed back from others trying to sort this out.

One issue i have, as this is my first exposure to the DD stuff, is that when you drag a column to the toolbar, and in the process the "blue arrows" for moving the column appear they still stay there after the drag event has finished.

My intent is to have a final working version within an week or so, it will be under an LGPL and be part of the JaffaRIA module under the jaffa.sf.net (That is where my team are sticking all our ExtJS extensions and DWR intergration)

Future things i want to do to it are
make sure it works with the filter plug-in (how can you filter on a grouped column if it has been hidden) should there be a dropdown against the column name in the toolbar too?)
get it working with some kind of paging store
integrate the store with DWR (as that is what my project uses to access the DB)
support some kind of Export to Excel...
get the groupTpl so that can do totaling of other columns, beyond the simple rs.length counting
like Animals demo drag and drop to re-order groups would be nice
full state management intergration so it remembers what you were grouping by last time


clone.id = Ext.id('ven');
clone.id = Ext.id(); This will not show error in FF but in ie it will show as object expected .

thanks for updates,

st_gross
8 Aug 2008, 11:24 AM
ut_paule live example here:

http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

Thanks ut_paule. Great work!!!!

P.D: Awesome screenshot in FF2!!!!!!

Indeed this looks great and is very promising!

A remaining problem seems to be column reordering after grouping.
Try to shift the Serial column left in the live example. You'll see the group title Part will
change to Serial after that. But this should be a minor issue (I hope)

Cheers
Stefan

DamienValentine
11 Aug 2008, 7:50 PM
Hi all. I found that code completelly independent and very useful. I got it to work in my application even when I have to create grids in a windows builded by xml templates. But I am a little bit confused with grouping by date. I can't get it to work and in provided example there is the same problem - each date is a group even when dates are the same. How to fight that?
p.s. sorry for my english :). i am ukrainian.
===added
In previous examples everything works fine...
Firebug gives "Row 18 added group. Values differ: prev= Wed Aug 06 2008 00:00:00 GMT+0300 curr= Wed Aug 06 2008 00:00:00 GMT+0300" but previous and current values are the same I guess :). I was thinking about checking field type and then format date to string but this is nonsense, besides in early posts this works fine.

galdaka
11 Aug 2008, 11:54 PM
Hi all. I found that code completelly independent and very useful. I got it to work in my application even when I have to create grids in a windows builded by xml templates. But I am a little bit confused with grouping by date. I can't get it to work and in provided example there is the same problem - each date is a group even when dates are the same. How to fight that?
p.s. sorry for my english :). i am ukrainian.
===added
In previous examples everything works fine...
Firebug gives "Row 18 added group. Values differ: prev= Wed Aug 06 2008 00:00:00 GMT+0300 curr= Wed Aug 06 2008 00:00:00 GMT+0300" but previous and current values are the same I guess :). I was thinking about checking field type and then format date to string but this is nonsense, besides in early posts this works fine.

http://www.jadacosta.es/extjs/exampl...ultiGroup.html (http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html)

DamienValentine
12 Aug 2008, 12:11 AM
Please, ungroup everything and group by ECD field then. If it works right for you and do not creates 6 groupes with the same name - please, give me know.

mcouillard
12 Aug 2008, 11:43 AM
Fantastic extension! Works very well out of the box. I can't wait to see how this evolves.

tchitani
12 Aug 2008, 3:50 PM
Hi

I just curios to know why the command like:

Ext.getCmp('ext-comp-1002').getStore().groupBy(['col_name1','col_name2'])

does not work from command line for the example provided.

Something is broken.

Regards
Nik

ut_paule
12 Aug 2008, 9:13 PM
Hi all. I found that code completelly independent and very useful. I got it to work in my application even when I have to create grids in a windows builded by xml templates. But I am a little bit confused with grouping by date. I can't get it to work and in provided example there is the same problem - each date is a group even when dates are the same. How to fight that?
p.s. sorry for my english :). i am ukrainian.


For some reason when doing the "not equal" check (!=) on the Date objects, it seems to fail, even if they are the same, as noted in the Firebug debug statements. The line in question is ...

if (lastvalues[j] != v) {
I'm not sure why javascript fails on this (help anyone?) as i assumed it would default to doing a toString() on the objects and then compare them. Because it did not i have explicitly used the toString() if we are comparing objects. With this following change the ECD grouping worked.

if ( (typeof(v)=="object" && (lastvalues[j].toString() != v.toString()) ) || (typeof(v)!="object" && (lastvalues[j] != v) ) ) {

I have a couple more tweaks I'm working on then I'll put out a new zip of the code. Meanwhile I'll attach the working screen shot...(I added sub-totaling in the groups for fun)

Enjoy

mystix
12 Aug 2008, 9:23 PM
just a thought:
are the time values (down to the milliseconds) on both Date objects the same?

might need to run clearTime() (http://extjs.com/docs/?class=Date&member=clearTime) on both if they're aren't.

DamienValentine
12 Aug 2008, 9:41 PM
the date is stored in mysql database and corresponding field has a type of 'date' not 'datetime'. so i am completely sure that the time values in any case are equal to something like 00:00:00.

if ( (typeof(v)=="object" && (lastvalues[j].toString() != v.toString()) ) || (typeof(v)!="object" && (lastvalues[j] != v) ) ) {
Converting to string works perfect. Currently searching for formatting date in group caption:

groupTextTpl: '{text} : {gvalue} ({[values.rs.length]} {[values.rs.length == 1 ? "запис" : "записів"]})',
to a Y-m-d format. If anyone knows the answer - please post your code.

ut_paule
12 Aug 2008, 9:47 PM
just a thought:
are the time values (down to the milliseconds) on both Date objects the same?

might need to run clearTime() (http://extjs.com/docs/?class=Date&member=clearTime) on both if they're aren't.

If you look at the JSON they are being created from (orders.json)

ecd: 'Aug 6, 2008',

There should be no time on any of them. The JSON should get parsed consistently in all cases, and have the same time.

I added the following debug


if(v instanceof Date)
console.debug(lastvalues[j].format("Y-m-d\\TH:i:s.uuu"), v.format("Y-m-d\\TH:i:s.uuu"));


And it gave this...


Row 2 added group. Values differ: prev= Wed Aug 06 2008 00:00:00 GMT-0700 (Pacific Daylight Time) curr= Wed Aug 06 2008 00:00:00 GMT-0700 (Pacific Daylight Time)
2008-08-06T00:00:00.000000000 2008-08-06T00:00:00.000000000


So i'm ruling out a millisecond issue.

If i perform the operation lastvalue[j]-v i get the answer 0 when they are the same which again is what i would expect for Date objects, so why == or != doesn't work is still a mystery to me :-?

mystix
12 Aug 2008, 9:57 PM
just fyi, the u format specifier is a single "u", not a sequence of "u"s.


someDate.format("Y-m-d\\TH:i:s.u")


just tested, and standard js doesn't seem to allow Date comparisons using the == / === comparators.
you're better off using something like


date1.getElapsed (http://extjs.com/docs/?class=Date&member=getElapsed)(date2) == 0;

ut_paule
12 Aug 2008, 10:13 PM
Hi

I just curios to know why the command like:

Ext.getCmp('ext-comp-1002').getStore().groupBy(['col_name1','col_name2'])

does not work from command line for the example provided.

Something is broken.

Regards
Nik

Looking at the code, it looks like the groupBy() can be used to just add one field to the list of grouping fields, so i expect to do what you want you should try

Ext.getCmp('ext-comp-1002').getStore().groupBy('col_name1');
Ext.getCmp('ext-comp-1002').getStore().groupBy('col_name2');

There is obviously room for improvement here. There is no simple method to set all the groups in one go, or to remove an individual group.

The way to do this directly is to modify the store.groupField and then invoke the datachanged event. Look at the following code which is used when a group is dragged off the toolbar and removed.



// Remove this group from the groupField array
var temp=[];
for(var i=this.panel.store.groupField.length-1;i>=0;i--) {
if(this.panel.store.groupField[i]==fld) {
this.panel.store.groupField.pop();
break;
}
temp.push(this.panel.store.groupField[i]);
this.panel.store.groupField.pop();
}

for(var i=temp.length-1;i>=0;i--) {
this.panel.store.groupField.push(temp[i]);
}

if(this.panel.store.groupField.length==0)
this.panel.store.groupField=false;

this.panel.store.fireEvent('datachanged', this);


I will try and add these convenience methods in the near future.

PaulE

DamienValentine
12 Aug 2008, 10:41 PM
I have made a quick solution to the date formatting. Piece of my code:

if (v) {
if (i == 0) {
// First record always starts a new group
if (typeof(v)=="object") {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:Ext.util.Format.date(v,'Y-m-d')});
} else {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
}
lastvalues[j] = v;
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
//gvalue.push(v);
} else {
if ((typeof(v)=="object" && (lastvalues[j].toString() != v.toString())) || (typeof(v)!="object" && (lastvalues[j] != v)) ) {
// This record is not in same group as previous one
console.debug("Row ",i," added group. Values differ: prev=",lastvalues[j]," curr=",v);
if (typeof(v)=="object") {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:Ext.util.Format.date(v,'Y-m-d')});
} else {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
}
lastvalues[j] = v;
//differ = 1;
changed = 1;
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else {
if (gfLen-1 == j && changed != 1) {
// This row is in all the same groups to the previous group
curGroup.rs.push(r);
console.debug("Row ",i," added to current group ",glbl);
} else if (changed == 1) {
// This group has changed because an earlier group changed.
if (typeof(v)=="object") {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:Ext.util.Format.date(v,'Y-m-d')});
} else {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
}
console.debug("Row ",i," added group. Higher level group change");
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else if(j<gfLen-1) {
// This is a parent group, and this record is part of this parent so add it
if(currGroups[fieldName])
currGroups[fieldName].rs.push(r);
else
console.error("Missing on row ",i," current group for ",fieldName);
}
}
}
} else {
if (this.displayEmptyFields) {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:this.emptyGroupText||'(none)'});
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ');
}
}
I wonder if anyone can make a more elegant solution with appropriate settings in configuration or something like this. Thanks for sharing, ut_paule!

galdaka
13 Aug 2008, 12:03 AM
Hi,


Please attach your modifications in a file for upload to my site and all the people can test.

Lastest example: http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html


Thanks in advance,

DamienValentine
13 Aug 2008, 2:24 AM
This is my MultiGrouping.js file. It can properly group date fields, but it uses static template for rendering group name. It will be like on screenshot (format is 'Y-m-d'). You can easily change this by searching 'Y-m-d' entries and replacing them with yours.

galdaka
13 Aug 2008, 5:26 AM
This is my MultiGrouping.js file. It can properly group date fields, but it uses static template for rendering group name. It will be like on screenshot (format is 'Y-m-d'). You can easily change this by searching 'Y-m-d' entries and replacing them with yours.

I upload your JS and not work. Please post me the correct JS in base of http://www.jadacosta.es/extjs/examples/multigroup/ux/MultiGrouping.js

Thanks in advance,

DamienValentine
13 Aug 2008, 9:15 PM
Hi. I am using EasyPHP 2.0. My multigroup example is located in folder named "Multigroup". I place this folder into c:\Program Files\EasyPHP 2.0b1\www\so it looks like c:\Program Files\EasyPHP 2.0b1\www\multigroup. Everything works fine. Try to run example from my zip. Then ungroup everything and group by ECD field. It must work.

galdaka
13 Aug 2008, 11:19 PM
Hi,

Sorry. provide me a full functional & simply Drag&Drop into EXT examples folder example.

I have not time for change paths & folders. With your example I change paths and not work:

Live example: http://www.jadacosta.es/extjs/examples/multigroup2/MultiGroup.html (http://www.jadacosta.es/extjs/examples/multigroup2/MultiGroup.html)


Thanks again,

nnextjs
16 Aug 2008, 10:43 AM
I tried the codes and could only make it work on Firefox.

tchitani
17 Aug 2008, 4:33 PM
The code perfectly works in both IE and Firefox (you just need to remove an extra commas in Multi.js script).
I think it will be very important to implement regrouping ("swapping") on a toolbar level, as well as multigroup removal/addition from a combobox (for example).

DamienValentine
17 Aug 2008, 10:34 PM
Galdaka, I will post my code soon. I have to change paths too :) and this will take some time. I will edit this post today and give you a full working example.

bvutukur
17 Aug 2008, 10:43 PM
The code perfectly works in both IE and Firefox (you just need to remove an extra commas in Multi.js script).
I think it will be very important to implement regrouping ("swapping") on a toolbar level, as well as multigroup removal/addition from a combobox (for example).

hi

i am getting an Object does not support erro in IE. when i am trying to drag column to tool bar. but i am not getting the above error in Firefox. when debug the code it is failing at the following line of ext-all-debug.js

var range = el.ownerDocument.createRange();

my multi.js is not having any extra commas. still i am getting the above error.

Thanks & Regards
bvutukur

DServe
20 Aug 2008, 1:30 AM
Hello,
I'm using the first 'stable' release of this excellent plugin here:
http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

while calling myContainer.remove(myMultigroupObject); I have an error on line 30730 of ext-all-debug.js (release 2.1) :


30721 if(this.grid.enableColumnMove){
30722 var dds = Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
30723 if(dds){
30724 for(var dd in dds){
30725 if(!dds[dd].config.isTarget && dds[dd].dragElId){
30726 var elid = dds[dd].dragElId;
30727 dds[dd].unreg();
30728 Ext.get(elid).remove();
30729 } else if(dds[dd].config.isTarget){
30730 dds[dd].proxyTop.remove();
30731 dds[dd].proxyBottom.remove();
30732 dds[dd].unreg();
30733 }
30734 if(Ext.dd.DDM.locationCache[dd]){
30735 delete Ext.dd.DDM.locationCache[dd];
30736 }
30737 }
30738 delete Ext.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
30739 }
30740 }Has anybody a fix for this error ? Maybe upgrading to Ext 2.2 will do ?

Edit : I upgraded to 2.2 and the problem is still present

Many thanks by advance
Damien

galdaka
20 Aug 2008, 1:05 PM
Galdaka, I will post my code soon. I have to change paths too :) and this will take some time. I will edit this post today and give you a full working example.

I can

jerrybrown5
21 Aug 2008, 5:03 AM
Venky0589,
This is a superb extension as is. However, this has great untapped potential as well. It seems very doable to use this multi-level grouping store within an XTemplate thus allowing DataViews and ComboBoxes to have multiple groupings--which leads me to my question. How is this being licensed?

Cheers,
Jerry

randymay
21 Aug 2008, 5:37 AM
I can see that the html page references a stylesheet called list.css which is supposed to be in ext/references/css. However, I cannot find this file in 2.0.2, 2.1, 2.2, or in the zip file. Am I missing something?

Thanks,

Randy

galdaka
21 Aug 2008, 5:43 AM
I can see that the html page references a stylesheet called list.css which is supposed to be in ext/references/css. However, I cannot find this file in 2.0.2, 2.1, 2.2, or in the zip file. Am I missing something?

Thanks,

Randy

http://www.jadacosta.es/extjs/exampl...ultiGroup.html

Greetings,

randymay
21 Aug 2008, 6:27 AM
The problem I am having is that I can render the grid header, and column header, but nothing else. There is no error reported, and I get the same behaviour in IE and FF. I thought it was a problem with a missing stylesheet, but now I'm not so sure. Has anyone seen this before?

galdaka
21 Aug 2008, 6:32 AM
The problem I am having is that I can render the grid header, and column header, but nothing else. There is no error reported, and I get the same behaviour in IE and FF. I thought it was a problem with a missing stylesheet, but now I'm not so sure. Has anyone seen this before?

Not work in local mode. Try my link.

Greetings,

randymay
21 Aug 2008, 6:37 AM
Not work in local mode. Try my link.

Greetings,

It works great from your link, but I am trying to get this running locally, so that it can be embedded into my application. What is different from your site VS what is in the zip file?

Thanks,

Randy

galdaka
21 Aug 2008, 6:42 AM
It works great from your link, but I am trying to get this running locally, so that it can be embedded into my application. What is different from your site VS what is in the zip file?

Thanks,

Randy

I think nothing but I attach ZIP file with the code of my website.

Greetings,

randymay
21 Aug 2008, 7:28 AM
I think nothing but I attach ZIP file with the code of my website.

Greetings,

Thank you for your help, and I found the problem; I (stupidly) failed to change the HttpProxy to use a local file on my machine.

Sorry,

Randy

venky0589
22 Aug 2008, 1:01 AM
Venky0589,
This is a superb extension as is. However, this has great untapped potential as well. It seems very doable to use this multi-level grouping store within an XTemplate thus allowing DataViews and ComboBoxes to have multiple groupings--which leads me to my question. How is this being licensed?

Cheers,
Jerry

Hi,
why do you ask this question ?

jerrybrown5
22 Aug 2008, 10:34 AM
Hi,
why do you ask this question ?

Isn't it sad that with so many different licenses and exceptions--doesn't every programmer need to ask about this now?

randymay
23 Aug 2008, 10:45 AM
Does anyone know how to configure the MultiGroupingPanel to produce an anchor tag where the values of the href attribute can be linked to one or more values from the data?

What I am trying to do is navigate to a URL when the User clicks on a row from the grid. The URL needs to be dynamically build for each row based on data from three different columns in that row.

For example, Vendor ID, Location ID, and Classification ID are in each column on the grid. I would like a tag like: <a href="http://localhost:8080/application/summary.jsp?vendor=32523&location=4325234&classification=528304" />.

Due to the nature of what I am trying to do, I cannot add a listener, and do a document.location.href. That would be easiest, but it won't work for what I need to do.

Any help would be greatly appreciated.

Thanks,

Randy

venky0589
25 Aug 2008, 12:23 AM
Isn't it sad that with so many different licenses and exceptions--doesn't every programmer need to ask about this now?

True but developers need to freed from understanding the legality of licenses and let him best do what he does,developing . since we are using community and contributed our code .... so use and modify and claim at your own risk and keep it simple

regards

jerrybrown5
25 Aug 2008, 1:03 AM
True but developers need to freed from understanding the legality of licenses and let him best do what he does,developing . since we are using community and contributed our code .... so use and modify and claim at your own risk and keep it simple

regards

I agree and I think this is what ext user extensions should be all about. I added a mod to your extension to clean up the code a little and for having custom group templates...


Here is the implementation update--


,groupFieldTemplates: {
contract:'custom template for *CONTRACT* whose value is {gvalue}'
,part:'custom template for *PART* whose value is {gvalue}'
,topworkorderno:'custom template for *TOPWORKORDERNO* whose value is {gvalue}'


The whole page:


/**
* @author chander
*/
Ext.onReady(function(){
Ext.QuickTips.init();

var WorkOrderRecord = Ext.data.Record.create([
{name: 'workOrderNo'}
,{name: 'contract'}
,{name: 'segregationCode'}
,{name: 'topWorkOrderNo'}
,{name: 'part'}
,{name: 'serial'}
,{name: 'span'}
,{name: 'ecd', type:'date'}
,{name: 'laborHours'}
,{name: 'materialCosts'}
]);

var columnModel = new Ext.grid.ColumnModel([{
header: 'Contract No'
,width: 100
,dataIndex: 'contract'
}, {
header: 'Segregation Code'
,width: 100
,dataIndex: 'segregationCode'
}, {
header: 'Top Work Order'
,width: 100
,dataIndex: 'topWorkOrderNo'
}, {
header: 'Work Order'
,width: 100
,dataIndex: 'workOrderNo'
}, {
header: 'Part'
,width: 100
,dataIndex: 'part'
}, {
header: 'Serial'
,width: 100
,dataIndex: 'serial'
,sortable: true
}, {
header: 'Span'
,width: 100
,dataIndex: 'span'
,align: 'right'
}, {
header: 'ECD'
,width: 100
,dataIndex: 'ecd'
}, {
header: 'Labor Hours'
,width: 100
,dataIndex: 'laborHours'
,align: 'right'
}, {
header: 'Material Costs'
,width: 100
,dataIndex: 'materialCosts'
,align: 'right'
}
]);


// create reader that reads into Topic records
var reader = new Ext.data.JsonReader({
totalProperty: 'total'
,root: 'rows'
,id: 'workOrderNo'
}, WorkOrderRecord);

var groupStore = new Ext.ux.MultiGroupingStore({
proxy: new Ext.data.HttpProxy({
url: 'orders.json',
method: 'GET'
})
,reader: reader
,sortInfo: {field: 'workOrderNo', direction: 'ASC'}
,groupField: ['contract','part','topWorkOrderNo']
,groupFieldTemplates: {
contract:'custom template for *CONTRACT* whose value is {gvalue}'
,part:'custom template for *PART* whose value is {gvalue}'
,topworkorderno:'custom template for *TOPWORKORDERNO* whose value is {gvalue}'
}
});

var groupView = new Ext.ux.MultiGroupingView({
hideGroupedColumn :true
,forceFit: true
,emptyGroupText: 'All Group Fields Empty'
,displayEmptyFields: true //you can choose to show the group fields, even when they have no values
// ,groupTextTpl: 'Help = {text} ' //({[values.rs.length]} {[values.rs.length > 1 ? "Records" : "Record"]})',
,groupTextTpl: '{text} : {gvalue} ({[values.rs.length]} {[values.rs.length == 1 ? "Record" : "Records"]})'
,displayFieldSeparator: ', ' //you can control how the display fields are seperated
});

//var grid = new Ext.grid.GridPanel({
var grid = new Ext.ux.MultiGroupingPanel({
store: groupStore
,cm:columnModel
,view: groupView
,width: 1024
,height: 600
,collapsible: true
,animCollapse: true
,title: 'Grouping Example'
,iconCls: 'icon-grid'
,renderTo: document.body
});

groupStore.load();

});
And here is the updated js file:


/**
* @author chander
*/


Ext.ux.MultiGroupingStore = Ext.extend(Ext.data.GroupingStore, {
constructor: function(config) {
Ext.ux.MultiGroupingStore.superclass.constructor.apply(this, arguments);
},

sortInfo: [],

sort: function(field, dir) {
var f = [];
if (Ext.isArray(field)) {
for (var i = 0, len = field.length; i < len; ++i) {
f.push(this.fields.get(field[i]));
}
} else {
f.push(this.fields.get(field));
}

if (f.length < 1) {
return false;
}

if (!dir) {
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].field == f[0].name) { // toggle sort dir
dir = (this.sortToggle[f[0].name] || "ASC").toggle("ASC", "DESC");
} else {
dir = f[0].sortDir;
}
}

var st = (this.sortToggle) ? this.sortToggle[f[0].name] : null;
var si = (this.sortInfo) ? this.sortInfo: null;

this.sortToggle[f[0].name] = dir;
this.sortInfo = [];
for (var i = 0, len = f.length; i < len; ++i) {
this.sortInfo.push({
field: f[i].name,
direction: dir
});
}

if (!this.remoteSort) {
this.applySort();
this.fireEvent("datachanged", this);
} else {
if (!this.load(this.lastOptions)) {
if (st) {
this.sortToggle[f[0].name] = st;
}
if (si) {
this.sortInfo = si;
}
}
}

},

setDefaultSort: function(field, dir) {
dir = dir ? dir.toUpperCase() : "ASC";
this.sortInfo = [];

if (!Ext.isArray(field)) {
this.sortInfo.push({
field: field,
direction: dir
});
} else {
for (var i = 0, len = field.length; i < len; ++i) {
this.sortInfo.push({
field: field[i].field,
direction: dir
});
this.sortToggle[field[i]] = dir;
}
}
},

groupBy: function(field, forceRegroup) {
if (!forceRegroup && this.groupField == field) {
return; // already grouped by this field
}

if (this.groupField) {
for (var z = 0; z < this.groupField.length; z++) if (field == this.groupField[z]) return;
this.groupField.push(field);
} else {
this.groupField = [field];
}

if (this.remoteGroup) {
if (!this.baseParams) {
this.baseParams = {};
}
this.baseParams['groupBy'] = field;
}
if (this.groupOnSort) {
this.sort(field);
return;
}
if (this.remoteGroup) {
this.reload();
} else {
var si = this.sortInfo || [];
if (si.field != field) {
this.applySort();
} else {
this.sortData(field);
}
this.fireEvent('datachanged', this);
}
},

applySort: function() {

var si = this.sortInfo;

if (si && si.length > 0 && !this.remoteSort) {
this.sortData(si, si[0].direction);
}

if (!this.groupOnSort && !this.remoteGroup) {
var gs = this.getGroupState();
if (gs && gs != this.sortInfo) {

this.sortData(this.groupField);
}
}
},

getGroupState: function() {
return this.groupOnSort && this.groupField !== false ? (this.sortInfo ? this.sortInfo: undefined) : this.groupField;
},

sortData: function(flist, direction) {
//alert('sortData '+ direction);
direction = direction || 'ASC';

var st = [];

var o;
for (var i = 0, len = flist.length; i < len; ++i) {
o = flist[i];
st.push(this.fields.get(o.field ? o.field: o).sortType);
}

var fn = function(r1, r2) {

var v1 = [];
var v2 = [];
var len = flist.length;
var o;
var name;

for (var i = 0; i < len; ++i) {
o = flist[i];
name = o.field ? o.field: o;

v1.push(st[i](r1.data[name]));
v2.push(st[i](r2.data[name]));
}

var result;
for (var i = 0; i < len; ++i) {
result = v1[i] > v2[i] ? 1 : (v1[i] < v2[i] ? -1 : 0);
if (result != 0) return result;
}

return result; //if it gets here, that means all fields are equal
};

this.data.sort(direction, fn);
if (this.snapshot && this.snapshot != this.data) {
this.snapshot.sort(direction, fn);
}
}

});

Ext.ux.MultiGroupingView = Ext.extend(Ext.grid.GroupingView, {
constructor: function(config) {
Ext.ux.MultiGroupingView.superclass.constructor.apply(this, arguments);
// Added so we can clear cached rows each time the view is refreshed
this.on("beforerefresh",
function() {
if (this.rowsCache) {
delete rowsCache;
}
},this);
},


displayEmptyFields: false,


displayFieldSeparator: ', ',


renderRows: function() {
var groupField = this.getGroupField();
var eg = !!groupField;
// if they turned off grouping and the last grouped field is hidden
if (this.hideGroupedColumn) {
var colIndexes = [];
for (var i = 0, len = groupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(groupField[i]);
if (cidx >= 0) {
colIndexes.push(cidx);
}
}
if (!eg && this.lastGroupField !== undefined) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) {
this.cm.setHidden(cidx, false);
} else {
alert("Unhide Col: " + cidx);
}
}
delete this.lastGroupField;
delete this.lgflen;
} else if (eg && colIndexes.length > 0 && this.lastGroupField === undefined) {
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
} else if (eg && this.lastGroupField !== undefined && (groupField !== this.lastGroupField || this.lgflen != this.lastGroupField.length)) {
this.mainBody.update('');
for (var i = 0,len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) {
this.cm.setHidden(cidx, false);
}
}
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
}
}
return Ext.ux.MultiGroupingView.superclass.renderRows.apply(this, arguments);
},

/** This sets up the toolbar for the grid based on what is grouped
* It also iterates over all the rows and figures out where each group should appeaer
* The store at this point is already stored based on the groups.
*/

doRender: function(cs, rs, ds, startRow, colCount, stripe) {
if (rs.length < 1) {
return '';
}

var groupField = this.getGroupField();
var gfLen = groupField.length;

var ss = this.grid.getTopToolbar();


if (ss){
// Remove all entries alreay in the toolbar
for (var hh = 0; hh < ss.items.length; hh++) {
Ext.removeNode(Ext.getDom(ss.items.itemAt(hh).id));
}

if (gfLen == 0) {
ss.addItem(new Ext.Toolbar.TextItem("Drop Columns Here To Group"));
} else {
// Add back all entries to toolbar from GroupField[]
ss.addItem(new Ext.Toolbar.TextItem("Grouped By:"));
for (var gfi = 0; gfi < gfLen; gfi++) {
var t = groupField[gfi];
if (gfi > 0) {
ss.addItem(new Ext.Toolbar.Separator());
}
var b = new Ext.Toolbar.Button({
text: this.cm.lookup[this.cm.findColumnIndex(t)].header
});
b.fieldName = t;
ss.addItem(b);
}
}
}

this.enableGrouping = !!groupField;

if (!this.enableGrouping || this.isUpdating) {
return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments);
}

var gstyle = 'width:' + this.getTotalWidth() + ';';
var gidPrefix = this.grid.getGridEl().id;
var groups = [], curGroup, i, len, gid;
var lastvalues = [];
var added = 0;
var currGroups = [];

// Create a specific style
var st = Ext.get(gidPrefix + "-style");
if (st) st.remove();
Ext.getDoc().child("head").createChild({
tag: 'style',
id: gidPrefix + "-style",
html: "div#" + gidPrefix + " div.x-grid3-row {padding-left:" + (gfLen * 12) + "px}" + "div#" + gidPrefix + " div.x-grid3-header {padding-left:" + (gfLen * 12) + "px}"
});

for (var i = 0, len = rs.length; i < len; i++) {
added = 0;
var rowIndex = startRow + i;
var r = rs[i];
var differ = 0;
var gvalue = [];
var fieldName;
var fieldLabel;
var grpFieldNames = [];
var grpFieldLabels = [];
var v;
var changed = 0;
var addGroup = [];

for (var j = 0; j < gfLen; j++) {
fieldName = groupField[j];
fieldLabel = this.cm.lookup[this.cm.findColumnIndex(fieldName)].header;
v = r.data[fieldName];
if (v) {
if (i == 0) {
// First record always starts a new group
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});
lastvalues[j] = v;

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
//gvalue.push(v); ????
} else {
if (lastvalues[j] != v) {
// This record is not in same group as previous one
//console.debug("Row ",i," added group. Values differ: prev=",lastvalues[j]," curr=",v);
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});
lastvalues[j] = v;
changed = 1;

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else {
if (gfLen - 1 == j && changed != 1) {
// This row is in all the same groups to the previous group
curGroup.rs.push(r);
} else if (changed == 1) {
// This group has changed because an earlier group changed.
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else if (j < gfLen - 1) {
// This is a parent group, and this record is part of this parent so add it
if (currGroups[fieldName]) {
currGroups[fieldName].rs.push(r);
}

}
}
}
} else {
if (this.displayEmptyFields) {
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: this.emptyGroupText || '(none)'
});
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ');
}
}
} //for j


for (var k = 0; k < addGroup.length; k++) {
var gp = addGroup[k];
g = gp.dataIndex;
var glbl = addGroup[k].header;
// There is no current group, or its not for the right field, so create one
gid = gidPrefix + '-gp-' + gp.dataIndex + '-' + Ext.util.Format.htmlEncode(gp.value);

// if state is defined use it, however state is in terms of expanded
// so negate it, otherwise use the default.
var isCollapsed = typeof this.state[gid] !== 'undefined' ? !this.state[gid] : this.startCollapsed;
var gcls = isCollapsed ? 'x-grid-group-collapsed': '';
curGroup = {
group: gp.dataIndex,
gvalue: gp.value,
text: gp.header,
groupId: gid,
startRow: rowIndex,
rs: [r],
cls: gcls,
style: gstyle + 'padding-left:' + (gp.idx * 12) + 'px;'
};
currGroups[gp.dataIndex] = curGroup;
groups.push(curGroup);
r._groupId = gid; // Associate this row to a group
} //for k
} //for i

var buf = [];
var toEnd = 0;
for (var ilen = 0, len = groups.length; ilen < len; ilen++) {
toEnd++;
var g = groups[ilen];
var leaf = g.group == groupField[gfLen - 1];
this.doMultiGroupStart(buf, g, cs, ds, colCount);

if (g.rs.length != 0 && leaf) {
buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call(this, cs, g.rs, ds, g.startRow, colCount, stripe);
}

if (leaf) {
var jj;
var gg = groups[ilen + 1];
if (gg != null) {
for (var jj = 0; jj < groupField.length; jj++) {
if (gg.group == groupField[jj]) {
break;
}
}
toEnd = groupField.length - jj;
}
for (var k = 0; k < toEnd; k++) {
this.doMultiGroupEnd(buf, g, cs, ds, colCount);
}
toEnd = jj;
}

}

return buf.join('');
},

initTemplates: function() {
Ext.grid.GroupingView.superclass.initTemplates.call(this);
this.state = {};

var sm = this.grid.getSelectionModel();
sm.on(sm.selectRow ? 'beforerowselect': 'beforecellselect', this.onBeforeRowSelect, this);

if (!this.startMultiGroup) {
this.startMultiGroup = new Ext.XTemplate('<div id="{groupId}" class="x-grid-group {cls}">', '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div>', this.groupTextTpl, '</div></div>', '<div id="{groupId}-bd" class="x-grid-group-body">');
}
this.startMultiGroup.compile();
this.endMultiGroup = '</div></div>';
},

doMultiGroupStart: function(buf, g, cs, ds, colCount) {
var groupName = g.group.toLowerCase(),
groupFieldTemplate;

if (ds.groupFieldTemplates && (groupFieldTemplate = ds.groupFieldTemplates[groupName])) {
if (typeof(groupFieldTemplate) == 'string') {
groupFieldTemplate = new Ext.XTemplate('<div id="{groupId}" class="x-grid-group {cls}">', '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div>', groupFieldTemplate, '</div></div>', '<div id="{groupId}-bd" class="x-grid-group-body">');
groupFieldTemplate.compile();
}
buf[buf.length] = groupFieldTemplate.apply(g);
} else {
buf[buf.length] = this.startMultiGroup.apply(g);
}

},


doMultiGroupEnd: function(buf, g, cs, ds, colCount) {
buf[buf.length] = this.endMultiGroup;
},

/** Should return an array of all elements that represent a row, it should bypass
* all grouping sections
*/
getRows: function() {

// This function is called may times, so use a cache if it is available
if (this.rowsCache) {
r = this.rowsCache.slice(0);
} else {
if (!this.enableGrouping) {
return Ext.grid.GroupingView.superclass.getRows.call(this);
}
var groupField = this.getGroupField();
var r = [];
var g, gs = this.getGroups();
// this.getGroups() contains an array of DIVS for the top level groups
r = this.getRowsFromGroup(r, gs, groupField[groupField.length - 1]);

// Clone the array, but not the objects in it
}
return r;
}

/** Return array of records under a given group
* @param r Record array to append to in the returned object
* @param gs Grouping Sections, an array of DIV element that represent a set of grouped records
* @param lsField The name of the grouping section we want to count
*/
,
getRowsFromGroup: function(r, gs, lsField) {
var rx = new RegExp(".*-gp-" + lsField + "-.*");

// Loop over each section
for (var i = 0, len = gs.length; i < len; i++) {

// Get group name for this section
var groupName = gs[i].id;
if (rx.test(groupName)) {
g = gs[i].childNodes[1].childNodes;
for (var j = 0, jlen = g.length; j < jlen; j++) {
r[r.length] = g[j];
}
} else {
if (!gs[i].childNodes[1]) {
} else {
r = this.getRowsFromGroup(r, gs[i].childNodes[1].childNodes, lsField);
}
}
}
return r;
}
});

Ext.ux.MultiGroupingPanel = function(config) {
config = config || {};
config.tbar = new Ext.Toolbar({
id: 'grid-tbr'
});
Ext.ux.MultiGroupingPanel.superclass.constructor.call(this, config);
};
Ext.extend(Ext.ux.MultiGroupingPanel, Ext.grid.GridPanel, {

initComponent: function() {
Ext.ux.MultiGroupingPanel.superclass.initComponent.call(this);

// Initialise DragZone
this.on("render", this.setUpDragging, this);
},

setUpDragging: function() {
this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
ddGroup: "grid-body",
panel: this,
scroll: false,
onInitDrag: function(e) {
// alert('init');
var clone = this.dragData.ddel;
clone.id = Ext.id('ven');
// clone.class='x-btn button';
this.proxy.update(clone);
return true;
},
getDragData: function(e) {
var target = Ext.get(e.getTarget().id);
if (target.hasClass('x-toolbar x-small-editor')) {
return false;
}

d = e.getTarget().cloneNode(true);
d.id = Ext.id();
//console.debug("getDragData",this, target);

this.dragData = {
repairXY: Ext.fly(target).getXY(),
ddel: d,
btn: e.getTarget()
};
return this.dragData;
}

//Provide coordinates for the proxy to slide back to on failed drag.
//This is the original XY coordinates of the draggable element.
,
getRepairXY: function() {
return this.dragData.repairXY;
}

});

// This is the target when columns are dropped onto the toolbar (ie added to the group)
this.dropTarget2s = new Ext.dd.DropTarget('grid-tbr', {
ddGroup: "gridHeader" + this.getGridEl().id,
panel: this,
notifyDrop: function(dd, e, data) {
var btname = this.panel.getColumnModel().getDataIndex(this.panel.getView().getCellIndex(data.header));
this.panel.store.groupBy(btname);
return true;
}
});

// This is the target when columns are dropped onto the grid (ie removed from the group)
this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
ddGroup: "grid-body",
panel: this,
notifyDrop: function(dd, e, data) {
var txt = Ext.get(data.btn).dom.innerHTML;
var tb = this.panel.getTopToolbar();
var bidx = tb.items.findIndexBy(function(b) {
return b.text == txt;
},this);
if (bidx < 0) return; // Error!
var fld = tb.items.get(bidx).fieldName;

// Remove from toolbar
Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
if (bidx > 0) {
Ext.removeNode(Ext.getDom(tb.items.get(bidx - 1).id));;
}

var cidx = this.panel.view.cm.findColumnIndex(fld);

this.panel.view.cm.setHidden(cidx, false);

var temp = [];

for (var i = this.panel.store.groupField.length - 1; i >= 0; i--) {
if (this.panel.store.groupField[i] == fld) {
this.panel.store.groupField.pop();
break;
}
temp.push(this.panel.store.groupField[i]);
this.panel.store.groupField.pop();
}

for (var i = temp.length - 1; i >= 0; i--) {
this.panel.store.groupField.push(temp[i]);
}

if (this.panel.store.groupField.length == 0) {
this.panel.store.groupField = false;
}

this.panel.store.fireEvent('datachanged', this);
return true;
}
});

}
});

galdaka
25 Aug 2008, 6:55 AM
Thanks jerrybrown5,

Your live example is in: http://www.jadacosta.es/extjs/examples/multigroup2/MultiGroup.html

For test pourposes.

P.D: Change in your example:


url: 'orders.html',

by


url: 'orders.json',


Greetings,

dhenning23
25 Aug 2008, 7:03 AM
This is a great extension, thanks to all! The problem I seeing is that with forcefit set to true the values on the rightmost column are truncated in Firefox. You can see this in the online example:

http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

Notice that the .12 is cut off in the Material Costs column, it should show 4002.12.

IE doesn't have this problem, but has another issue: the detail rows under the grouping are not indented on the left side. You can see this at the same link above.

I tried playing around with the CSS to fix the IE issue, but I don't know enough about CSS. Any help would be appreciated.

Thanks,

Doug

mdissel
29 Aug 2008, 3:15 AM
Nice extension!! Any one already tried to make the group values configurable?
Sample:
* groupby datetime field, but show values like today, yesterday, etc.
* groupby part of the fieldvalue (fieldvalue = 'a;b;c', it should create three groups..) and show this single record in the three groups (for a live example see MS Outlook and group on Categories field with multiple category values)

maybe something like change the compare value function in the doRender method tp to a function call that returns a single groupvalue (change date into "today", tomorrow" or return an array [a,b,c] when 'a;b;c') and create the correct grouping structure..

Thanks
Marco

ut_paule
3 Sep 2008, 9:52 PM
I final got time to clean up my code, and I've posted it to the jaffa sourceforge project and deploy a working version for you all to see. Here is the link http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html

I have included links to all the relevant code in CVS, as well as a change log, and details of which issues mentioned on this thread that have been fixed (thanks for the input)

I have put this code under an LGPL, even though ExtJS is under a GPL. Hope that works for all.

I will continue to work through the other issues on the list as time permits

PaulE

galdaka
4 Sep 2008, 3:57 AM
I final got time to clean up my code, and I've posted it to the jaffa sourceforge project and deploy a working version for you all to see. Here is the link http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html

I have included links to all the relevant code in CVS, as well as a change log, and details of which issues mentioned on this thread that have been fixed (thanks for the input)

I have put this code under an LGPL, even though ExtJS is under a GPL. Hope that works for all.

I will continue to work through the other issues on the list as time permits

PaulE

I can

tchitani
8 Sep 2008, 9:24 PM
Hi

Adding Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); breaks the extention:

f[0] has no properties
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].fi... in Firebug

Thanks
Nik

ENEMYoftheSUN
9 Sep 2008, 1:26 AM
Hi

Adding Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); breaks the extention:

f[0] has no properties
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].fi... in Firebug

Thanks
Nik
Hello

you may add "stateful: false" on your grid config to bypass this error.
Hope it helps.

tchitani
9 Sep 2008, 1:53 AM
Thanks

I do know that, but I need statefull: true

ljkmchale
9 Sep 2008, 8:22 AM
I have noticed a couple of things that are no longer working. I am comparing this new grid (which is fantastic) to the standard grouping grid.

1. The rowIndex no longer works in an event function when grouping is turned on.
Example: whatever.on("rowdblclick", function(grid, rowIndex, e) {console.debug("rowIndex: " + rowIndex)}
2. The mouseover events no longer fire when grouping is on. On the grouping grid you can hover over a row with your mouse and the row will highlight.
3. The little sort arrow no longer appears at any time.

Any clues, or is it just me? :)

hpandey
9 Sep 2008, 8:42 AM
I am having problem making the summary for Multi Level Group. It is implemented for single level grouping already. Has anybody tried or done that before, please let me know? Would be great help.

Harsh


I agree and I think this is what ext user extensions should be all about. I added a mod to your extension to clean up the code a little and for having custom group templates...


Here is the implementation update--


,groupFieldTemplates: {
contract:'custom template for *CONTRACT* whose value is {gvalue}'
,part:'custom template for *PART* whose value is {gvalue}'
,topworkorderno:'custom template for *TOPWORKORDERNO* whose value is {gvalue}'
The whole page:


/**
* @author chander
*/
Ext.onReady(function(){
Ext.QuickTips.init();

var WorkOrderRecord = Ext.data.Record.create([
{name: 'workOrderNo'}
,{name: 'contract'}
,{name: 'segregationCode'}
,{name: 'topWorkOrderNo'}
,{name: 'part'}
,{name: 'serial'}
,{name: 'span'}
,{name: 'ecd', type:'date'}
,{name: 'laborHours'}
,{name: 'materialCosts'}
]);

var columnModel = new Ext.grid.ColumnModel([{
header: 'Contract No'
,width: 100
,dataIndex: 'contract'
}, {
header: 'Segregation Code'
,width: 100
,dataIndex: 'segregationCode'
}, {
header: 'Top Work Order'
,width: 100
,dataIndex: 'topWorkOrderNo'
}, {
header: 'Work Order'
,width: 100
,dataIndex: 'workOrderNo'
}, {
header: 'Part'
,width: 100
,dataIndex: 'part'
}, {
header: 'Serial'
,width: 100
,dataIndex: 'serial'
,sortable: true
}, {
header: 'Span'
,width: 100
,dataIndex: 'span'
,align: 'right'
}, {
header: 'ECD'
,width: 100
,dataIndex: 'ecd'
}, {
header: 'Labor Hours'
,width: 100
,dataIndex: 'laborHours'
,align: 'right'
}, {
header: 'Material Costs'
,width: 100
,dataIndex: 'materialCosts'
,align: 'right'
}
]);


// create reader that reads into Topic records
var reader = new Ext.data.JsonReader({
totalProperty: 'total'
,root: 'rows'
,id: 'workOrderNo'
}, WorkOrderRecord);

var groupStore = new Ext.ux.MultiGroupingStore({
proxy: new Ext.data.HttpProxy({
url: 'orders.json',
method: 'GET'
})
,reader: reader
,sortInfo: {field: 'workOrderNo', direction: 'ASC'}
,groupField: ['contract','part','topWorkOrderNo']
,groupFieldTemplates: {
contract:'custom template for *CONTRACT* whose value is {gvalue}'
,part:'custom template for *PART* whose value is {gvalue}'
,topworkorderno:'custom template for *TOPWORKORDERNO* whose value is {gvalue}'
}
});

var groupView = new Ext.ux.MultiGroupingView({
hideGroupedColumn :true
,forceFit: true
,emptyGroupText: 'All Group Fields Empty'
,displayEmptyFields: true //you can choose to show the group fields, even when they have no values
// ,groupTextTpl: 'Help = {text} ' //({[values.rs.length]} {[values.rs.length > 1 ? "Records" : "Record"]})',
,groupTextTpl: '{text} : {gvalue} ({[values.rs.length]} {[values.rs.length == 1 ? "Record" : "Records"]})'
,displayFieldSeparator: ', ' //you can control how the display fields are seperated
});

//var grid = new Ext.grid.GridPanel({
var grid = new Ext.ux.MultiGroupingPanel({
store: groupStore
,cm:columnModel
,view: groupView
,width: 1024
,height: 600
,collapsible: true
,animCollapse: true
,title: 'Grouping Example'
,iconCls: 'icon-grid'
,renderTo: document.body
});

groupStore.load();

});
And here is the updated js file:


/**
* @author chander
*/


Ext.ux.MultiGroupingStore = Ext.extend(Ext.data.GroupingStore, {
constructor: function(config) {
Ext.ux.MultiGroupingStore.superclass.constructor.apply(this, arguments);
},

sortInfo: [],

sort: function(field, dir) {
var f = [];
if (Ext.isArray(field)) {
for (var i = 0, len = field.length; i < len; ++i) {
f.push(this.fields.get(field[i]));
}
} else {
f.push(this.fields.get(field));
}

if (f.length < 1) {
return false;
}

if (!dir) {
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].field == f[0].name) { // toggle sort dir
dir = (this.sortToggle[f[0].name] || "ASC").toggle("ASC", "DESC");
} else {
dir = f[0].sortDir;
}
}

var st = (this.sortToggle) ? this.sortToggle[f[0].name] : null;
var si = (this.sortInfo) ? this.sortInfo: null;

this.sortToggle[f[0].name] = dir;
this.sortInfo = [];
for (var i = 0, len = f.length; i < len; ++i) {
this.sortInfo.push({
field: f[i].name,
direction: dir
});
}

if (!this.remoteSort) {
this.applySort();
this.fireEvent("datachanged", this);
} else {
if (!this.load(this.lastOptions)) {
if (st) {
this.sortToggle[f[0].name] = st;
}
if (si) {
this.sortInfo = si;
}
}
}

},

setDefaultSort: function(field, dir) {
dir = dir ? dir.toUpperCase() : "ASC";
this.sortInfo = [];

if (!Ext.isArray(field)) {
this.sortInfo.push({
field: field,
direction: dir
});
} else {
for (var i = 0, len = field.length; i < len; ++i) {
this.sortInfo.push({
field: field[i].field,
direction: dir
});
this.sortToggle[field[i]] = dir;
}
}
},

groupBy: function(field, forceRegroup) {
if (!forceRegroup && this.groupField == field) {
return; // already grouped by this field
}

if (this.groupField) {
for (var z = 0; z < this.groupField.length; z++) if (field == this.groupField[z]) return;
this.groupField.push(field);
} else {
this.groupField = [field];
}

if (this.remoteGroup) {
if (!this.baseParams) {
this.baseParams = {};
}
this.baseParams['groupBy'] = field;
}
if (this.groupOnSort) {
this.sort(field);
return;
}
if (this.remoteGroup) {
this.reload();
} else {
var si = this.sortInfo || [];
if (si.field != field) {
this.applySort();
} else {
this.sortData(field);
}
this.fireEvent('datachanged', this);
}
},

applySort: function() {

var si = this.sortInfo;

if (si && si.length > 0 && !this.remoteSort) {
this.sortData(si, si[0].direction);
}

if (!this.groupOnSort && !this.remoteGroup) {
var gs = this.getGroupState();
if (gs && gs != this.sortInfo) {

this.sortData(this.groupField);
}
}
},

getGroupState: function() {
return this.groupOnSort && this.groupField !== false ? (this.sortInfo ? this.sortInfo: undefined) : this.groupField;
},

sortData: function(flist, direction) {
//alert('sortData '+ direction);
direction = direction || 'ASC';

var st = [];

var o;
for (var i = 0, len = flist.length; i < len; ++i) {
o = flist[i];
st.push(this.fields.get(o.field ? o.field: o).sortType);
}

var fn = function(r1, r2) {

var v1 = [];
var v2 = [];
var len = flist.length;
var o;
var name;

for (var i = 0; i < len; ++i) {
o = flist[i];
name = o.field ? o.field: o;

v1.push(st[i](r1.data[name]));
v2.push(st[i](r2.data[name]));
}

var result;
for (var i = 0; i < len; ++i) {
result = v1[i] > v2[i] ? 1 : (v1[i] < v2[i] ? -1 : 0);
if (result != 0) return result;
}

return result; //if it gets here, that means all fields are equal
};

this.data.sort(direction, fn);
if (this.snapshot && this.snapshot != this.data) {
this.snapshot.sort(direction, fn);
}
}

});

Ext.ux.MultiGroupingView = Ext.extend(Ext.grid.GroupingView, {
constructor: function(config) {
Ext.ux.MultiGroupingView.superclass.constructor.apply(this, arguments);
// Added so we can clear cached rows each time the view is refreshed
this.on("beforerefresh",
function() {
if (this.rowsCache) {
delete rowsCache;
}
},this);
},


displayEmptyFields: false,


displayFieldSeparator: ', ',


renderRows: function() {
var groupField = this.getGroupField();
var eg = !!groupField;
// if they turned off grouping and the last grouped field is hidden
if (this.hideGroupedColumn) {
var colIndexes = [];
for (var i = 0, len = groupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(groupField[i]);
if (cidx >= 0) {
colIndexes.push(cidx);
}
}
if (!eg && this.lastGroupField !== undefined) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) {
this.cm.setHidden(cidx, false);
} else {
alert("Unhide Col: " + cidx);
}
}
delete this.lastGroupField;
delete this.lgflen;
} else if (eg && colIndexes.length > 0 && this.lastGroupField === undefined) {
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
} else if (eg && this.lastGroupField !== undefined && (groupField !== this.lastGroupField || this.lgflen != this.lastGroupField.length)) {
this.mainBody.update('');
for (var i = 0,len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) {
this.cm.setHidden(cidx, false);
}
}
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
}
}
return Ext.ux.MultiGroupingView.superclass.renderRows.apply(this, arguments);
},

/** This sets up the toolbar for the grid based on what is grouped
* It also iterates over all the rows and figures out where each group should appeaer
* The store at this point is already stored based on the groups.
*/

doRender: function(cs, rs, ds, startRow, colCount, stripe) {
if (rs.length < 1) {
return '';
}

var groupField = this.getGroupField();
var gfLen = groupField.length;

var ss = this.grid.getTopToolbar();


if (ss){
// Remove all entries alreay in the toolbar
for (var hh = 0; hh < ss.items.length; hh++) {
Ext.removeNode(Ext.getDom(ss.items.itemAt(hh).id));
}

if (gfLen == 0) {
ss.addItem(new Ext.Toolbar.TextItem("Drop Columns Here To Group"));
} else {
// Add back all entries to toolbar from GroupField[]
ss.addItem(new Ext.Toolbar.TextItem("Grouped By:"));
for (var gfi = 0; gfi < gfLen; gfi++) {
var t = groupField[gfi];
if (gfi > 0) {
ss.addItem(new Ext.Toolbar.Separator());
}
var b = new Ext.Toolbar.Button({
text: this.cm.lookup[this.cm.findColumnIndex(t)].header
});
b.fieldName = t;
ss.addItem(b);
}
}
}

this.enableGrouping = !!groupField;

if (!this.enableGrouping || this.isUpdating) {
return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments);
}

var gstyle = 'width:' + this.getTotalWidth() + ';';
var gidPrefix = this.grid.getGridEl().id;
var groups = [], curGroup, i, len, gid;
var lastvalues = [];
var added = 0;
var currGroups = [];

// Create a specific style
var st = Ext.get(gidPrefix + "-style");
if (st) st.remove();
Ext.getDoc().child("head").createChild({
tag: 'style',
id: gidPrefix + "-style",
html: "div#" + gidPrefix + " div.x-grid3-row {padding-left:" + (gfLen * 12) + "px}" + "div#" + gidPrefix + " div.x-grid3-header {padding-left:" + (gfLen * 12) + "px}"
});

for (var i = 0, len = rs.length; i < len; i++) {
added = 0;
var rowIndex = startRow + i;
var r = rs[i];
var differ = 0;
var gvalue = [];
var fieldName;
var fieldLabel;
var grpFieldNames = [];
var grpFieldLabels = [];
var v;
var changed = 0;
var addGroup = [];

for (var j = 0; j < gfLen; j++) {
fieldName = groupField[j];
fieldLabel = this.cm.lookup[this.cm.findColumnIndex(fieldName)].header;
v = r.data[fieldName];
if (v) {
if (i == 0) {
// First record always starts a new group
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});
lastvalues[j] = v;

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
//gvalue.push(v); ????
} else {
if (lastvalues[j] != v) {
// This record is not in same group as previous one
//console.debug("Row ",i," added group. Values differ: prev=",lastvalues[j]," curr=",v);
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});
lastvalues[j] = v;
changed = 1;

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else {
if (gfLen - 1 == j && changed != 1) {
// This row is in all the same groups to the previous group
curGroup.rs.push(r);
} else if (changed == 1) {
// This group has changed because an earlier group changed.
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: v
});

gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
} else if (j < gfLen - 1) {
// This is a parent group, and this record is part of this parent so add it
if (currGroups[fieldName]) {
currGroups[fieldName].rs.push(r);
}

}
}
}
} else {
if (this.displayEmptyFields) {
addGroup.push({
idx: j,
dataIndex: fieldName,
header: fieldLabel,
value: this.emptyGroupText || '(none)'
});
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ');
}
}
} //for j


for (var k = 0; k < addGroup.length; k++) {
var gp = addGroup[k];
g = gp.dataIndex;
var glbl = addGroup[k].header;
// There is no current group, or its not for the right field, so create one
gid = gidPrefix + '-gp-' + gp.dataIndex + '-' + Ext.util.Format.htmlEncode(gp.value);

// if state is defined use it, however state is in terms of expanded
// so negate it, otherwise use the default.
var isCollapsed = typeof this.state[gid] !== 'undefined' ? !this.state[gid] : this.startCollapsed;
var gcls = isCollapsed ? 'x-grid-group-collapsed': '';
curGroup = {
group: gp.dataIndex,
gvalue: gp.value,
text: gp.header,
groupId: gid,
startRow: rowIndex,
rs: [r],
cls: gcls,
style: gstyle + 'padding-left:' + (gp.idx * 12) + 'px;'
};
currGroups[gp.dataIndex] = curGroup;
groups.push(curGroup);
r._groupId = gid; // Associate this row to a group
} //for k
} //for i

var buf = [];
var toEnd = 0;
for (var ilen = 0, len = groups.length; ilen < len; ilen++) {
toEnd++;
var g = groups[ilen];
var leaf = g.group == groupField[gfLen - 1];
this.doMultiGroupStart(buf, g, cs, ds, colCount);

if (g.rs.length != 0 && leaf) {
buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call(this, cs, g.rs, ds, g.startRow, colCount, stripe);
}

if (leaf) {
var jj;
var gg = groups[ilen + 1];
if (gg != null) {
for (var jj = 0; jj < groupField.length; jj++) {
if (gg.group == groupField[jj]) {
break;
}
}
toEnd = groupField.length - jj;
}
for (var k = 0; k < toEnd; k++) {
this.doMultiGroupEnd(buf, g, cs, ds, colCount);
}
toEnd = jj;
}

}

return buf.join('');
},

initTemplates: function() {
Ext.grid.GroupingView.superclass.initTemplates.call(this);
this.state = {};

var sm = this.grid.getSelectionModel();
sm.on(sm.selectRow ? 'beforerowselect': 'beforecellselect', this.onBeforeRowSelect, this);

if (!this.startMultiGroup) {
this.startMultiGroup = new Ext.XTemplate('<div id="{groupId}" class="x-grid-group {cls}">', '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div>', this.groupTextTpl, '</div></div>', '<div id="{groupId}-bd" class="x-grid-group-body">');
}
this.startMultiGroup.compile();
this.endMultiGroup = '</div></div>';
},

doMultiGroupStart: function(buf, g, cs, ds, colCount) {
var groupName = g.group.toLowerCase(),
groupFieldTemplate;

if (ds.groupFieldTemplates && (groupFieldTemplate = ds.groupFieldTemplates[groupName])) {
if (typeof(groupFieldTemplate) == 'string') {
groupFieldTemplate = new Ext.XTemplate('<div id="{groupId}" class="x-grid-group {cls}">', '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div>', groupFieldTemplate, '</div></div>', '<div id="{groupId}-bd" class="x-grid-group-body">');
groupFieldTemplate.compile();
}
buf[buf.length] = groupFieldTemplate.apply(g);
} else {
buf[buf.length] = this.startMultiGroup.apply(g);
}

},


doMultiGroupEnd: function(buf, g, cs, ds, colCount) {
buf[buf.length] = this.endMultiGroup;
},

/** Should return an array of all elements that represent a row, it should bypass
* all grouping sections
*/
getRows: function() {

// This function is called may times, so use a cache if it is available
if (this.rowsCache) {
r = this.rowsCache.slice(0);
} else {
if (!this.enableGrouping) {
return Ext.grid.GroupingView.superclass.getRows.call(this);
}
var groupField = this.getGroupField();
var r = [];
var g, gs = this.getGroups();
// this.getGroups() contains an array of DIVS for the top level groups
r = this.getRowsFromGroup(r, gs, groupField[groupField.length - 1]);

// Clone the array, but not the objects in it
}
return r;
}

/** Return array of records under a given group
* @param r Record array to append to in the returned object
* @param gs Grouping Sections, an array of DIV element that represent a set of grouped records
* @param lsField The name of the grouping section we want to count
*/
,
getRowsFromGroup: function(r, gs, lsField) {
var rx = new RegExp(".*-gp-" + lsField + "-.*");

// Loop over each section
for (var i = 0, len = gs.length; i < len; i++) {

// Get group name for this section
var groupName = gs[i].id;
if (rx.test(groupName)) {
g = gs[i].childNodes[1].childNodes;
for (var j = 0, jlen = g.length; j < jlen; j++) {
r[r.length] = g[j];
}
} else {
if (!gs[i].childNodes[1]) {
} else {
r = this.getRowsFromGroup(r, gs[i].childNodes[1].childNodes, lsField);
}
}
}
return r;
}
});

Ext.ux.MultiGroupingPanel = function(config) {
config = config || {};
config.tbar = new Ext.Toolbar({
id: 'grid-tbr'
});
Ext.ux.MultiGroupingPanel.superclass.constructor.call(this, config);
};
Ext.extend(Ext.ux.MultiGroupingPanel, Ext.grid.GridPanel, {

initComponent: function() {
Ext.ux.MultiGroupingPanel.superclass.initComponent.call(this);

// Initialise DragZone
this.on("render", this.setUpDragging, this);
},

setUpDragging: function() {
this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
ddGroup: "grid-body",
panel: this,
scroll: false,
onInitDrag: function(e) {
// alert('init');
var clone = this.dragData.ddel;
clone.id = Ext.id('ven');
// clone.class='x-btn button';
this.proxy.update(clone);
return true;
},
getDragData: function(e) {
var target = Ext.get(e.getTarget().id);
if (target.hasClass('x-toolbar x-small-editor')) {
return false;
}

d = e.getTarget().cloneNode(true);
d.id = Ext.id();
//console.debug("getDragData",this, target);

this.dragData = {
repairXY: Ext.fly(target).getXY(),
ddel: d,
btn: e.getTarget()
};
return this.dragData;
}

//Provide coordinates for the proxy to slide back to on failed drag.
//This is the original XY coordinates of the draggable element.
,
getRepairXY: function() {
return this.dragData.repairXY;
}

});

// This is the target when columns are dropped onto the toolbar (ie added to the group)
this.dropTarget2s = new Ext.dd.DropTarget('grid-tbr', {
ddGroup: "gridHeader" + this.getGridEl().id,
panel: this,
notifyDrop: function(dd, e, data) {
var btname = this.panel.getColumnModel().getDataIndex(this.panel.getView().getCellIndex(data.header));
this.panel.store.groupBy(btname);
return true;
}
});

// This is the target when columns are dropped onto the grid (ie removed from the group)
this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
ddGroup: "grid-body",
panel: this,
notifyDrop: function(dd, e, data) {
var txt = Ext.get(data.btn).dom.innerHTML;
var tb = this.panel.getTopToolbar();
var bidx = tb.items.findIndexBy(function(b) {
return b.text == txt;
},this);
if (bidx < 0) return; // Error!
var fld = tb.items.get(bidx).fieldName;

// Remove from toolbar
Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
if (bidx > 0) {
Ext.removeNode(Ext.getDom(tb.items.get(bidx - 1).id));;
}

var cidx = this.panel.view.cm.findColumnIndex(fld);

this.panel.view.cm.setHidden(cidx, false);

var temp = [];

for (var i = this.panel.store.groupField.length - 1; i >= 0; i--) {
if (this.panel.store.groupField[i] == fld) {
this.panel.store.groupField.pop();
break;
}
temp.push(this.panel.store.groupField[i]);
this.panel.store.groupField.pop();
}

for (var i = temp.length - 1; i >= 0; i--) {
this.panel.store.groupField.push(temp[i]);
}

if (this.panel.store.groupField.length == 0) {
this.panel.store.groupField = false;
}

this.panel.store.fireEvent('datachanged', this);
return true;
}
});

}
});

ljkmchale
10 Sep 2008, 12:14 PM
So,

I took this great extension and used it with the dynamic grid extension plus the eventgrouping extension and came up with a dynamic multigrouping grid from the three. All extensions are great. If you are interested, please respond to this post and I will put the code up. I still need to figure out how to get the items mentioned in post #72 working, but the rest work nicely.:D

mdissel
10 Sep 2008, 12:40 PM
I took this great extension and used it with the dynamic grid extension plus the eventgrouping extension and came up with a dynamic multigrouping grid from the three. All extensions are great. If you are interested, please respond to this post and I will put the code up. I still need to figure out how to get the items mentioned in post #72 working, but the rest work nicely.:D

Every extension is welcome! Thanks

galdaka
10 Sep 2008, 12:46 PM
So,

I took this great extension and used it with the dynamic grid extension plus the eventgrouping extension and came up with a dynamic multigrouping grid from the three. All extensions are great. If you are interested, please respond to this post and I will put the code up. I still need to figure out how to get the items mentioned in post #72 working, but the rest work nicely.:D

sounds great!!

ljkmchale
11 Sep 2008, 4:14 AM
OK Folks;

I hope this works for all of you out there. I still have not figured out why the rowIndex is not working, but I am using this extension and It seems to work great.

MultigroupingPanel: This now has the DynamicColumnModel, DynamicXmlReader , DynamicGridPanel and MultiGroupingPanel in it.



Ext.grid.DynamicColumnModel = function(store) {
var cols = [];
var recordType = store.reader.recordType;
var fields = recordType.prototype.fields;

if ( fields.length == 0 )
{
fields = store.reader.headers;
cols[0] = {
id: 0,
menuDisabled : false,
header: '<img src="./images/12-em-check.png">',
dataIndex: 'check',
tooltip: '',
width: 35,
renderer: function(value,atts){
return value;
}
};
for ( var i = 0; i < store.reader.headers.length; i++ )
{
var header = store.reader.headers[i];
cols[i+1] = {
header: header.text,
dataIndex: header.name,
tooltip: '',
hidden: header.hidden,
width: parseInt(header.width),
renderer: function(value,atts){
value = "<span ext:qtip='" + Ext.util.Format.htmlEncode(value) + "'>" + value + "</span>";
return value;
}
};
}
}
else
{
//console.debug ("Run DynamicColumnModel");
cols[0] = {
id: 0,
menuDisabled : false,
hideable : false,
header: '<img src="./images/12-em-check.png">',
dataIndex: 'check',
tooltip: '',
width: 35,
renderer: function(value,atts){
return value;
}
};
for (var i = 0; i < fields.keys.length; i++) {
var fieldName = fields.keys[i];
var field = recordType.getField(fieldName);
//console.debug (field.name + ":" + field.width);
cols[i+1] = {
header: field.header,
dataIndex: field.name,
tooltip: field.tooltip,
hidden: field.hidden,
width: parseInt(field.width),
sortable: true, //for sorting
renderer: function(value,atts){
value = "<span ext:qtip='" + Ext.util.Format.htmlEncode(value) + "'>" + value + "</span>";
return value;
}
};
}
}
// for sorting
store.fields = store.reader.recordType.prototype.fields;

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.recordDefinition + ' > *', data);
var arr = [];
for (var i = 0; i < recordDefinition.length; i++) {
arr[i] = {
name: recordDefinition[i].tagName,
header: recordDefinition[i].getAttribute('header'),
tooltip: recordDefinition[i].getAttribute('tooltip'),
width: recordDefinition[i].getAttribute('width'),
hidden: recordDefinition[i].getAttribute('hidden') == "true" ? true : false
};
}

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("configchange", this.onColConfigChange, this);
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);
}
if(cm){
cm.on("configchange", this.onColConfigChange, this);
cm.on("widthchange", this.updateColumns, this);
cm.on("headerchange", this.updateHeaders, this);
cm.on("hiddenchange", this.handleHiddenChange, this);
cm.on("columnmoved", this.handleColumnMove, this);
}
this.cm = cm;
};

Ext.grid.DynamicGridPanel = function(config) {
this.trackMouseOver = config.trackMouseOver;
this.resizable = config.resizable;
this.bodyBorder = config.bodyBorder;
this.store = config.store;
this.renderTo = config.renderTo;
this.view = config.view;
this.tbar = config.tbar;
this.bbar = config.bbar;
this.plugins = config.plugins;
this.listeners = config.listeners;
Ext.grid.DynamicGridPanel.superclass.constructor.call(this, this.renderTo, config);
};
Ext.extend(Ext.grid.DynamicGridPanel, Ext.grid.GridPanel, {
render : function() {
this.store.addListener('load', this.doReconfiguration, this);
this.store.addEvents({afterload: true});
this.store.addListener('afterload', this.afterload, this);
this.colModel = new Ext.grid.DefaultColumnModel([{ header: '', dataIndex: '' }]);
var view = this.getView();
view.init(this);
Ext.grid.DynamicGridPanel.superclass.render.call(this);
},

doReconfiguration : function() {
this.colModel = new Ext.grid.DynamicColumnModel(this.store);
this.view.bindColumnModel(this.colModel);
this.view.refresh(true);
this.store.removeListener("load", this.doReconfiguration);
this.store.fireEvent('afterload',this.view);
},

afterload : function(){
//this.store.removeListener('afterload', this.afterload);
}
});


Ext.namespace("Ext.ux.grid");

Ext.ux.grid.MultiGroupingPanel = function(config) {
config.tbar = new Ext.Toolbar({id:'grid-tbr'}); //FIXME is this hardcoded id needed?
Ext.ux.grid.MultiGroupingPanel.superclass.constructor.call(this, config);
//console.debug ("Create MultiGroupingPanel",config);
};
Ext.extend(Ext.ux.grid.MultiGroupingPanel, Ext.grid.DynamicGridPanel, {

initComponent : function(config){
//console.debug ("MultiGroupingPanel.initComponent",this);
config = config||{};
Ext.ux.grid.MultiGroupingPanel.superclass.initComponent.call(this,config);

// Initialize DragZone
this.on("render", this.setUpDragging, this);
}

,setUpDragging: function() {
////console.debug ("SetUpDragging", this);
this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
ddGroup:"grid-body" + this.getGridEl().id //FIXME - does this need to be unique to support multiple independant panels on the same page
,panel:this
,scroll:false
// @todo - docs
,onInitDrag : function(e) {
// console.debug('init');
var clone = this.dragData.ddel;
clone.id = Ext.id('ven'); //FIXME??
// clone.class='x-btn button';
this.proxy.update(clone);
return true;
}

// @todo - docs
,getDragData: function(e) {
var target = Ext.get(e.getTarget().id);
if(target.hasClass('x-toolbar x-small-editor')) {
return false;
}

d = e.getTarget().cloneNode(true);
d.id = Ext.id();
//console.debug ("getDragData",this, target);

this.dragData = {
repairXY: Ext.fly(target).getXY(),
ddel: d,
btn:e.getTarget()
};
return this.dragData;
}

//Provide coordinates for the proxy to slide back to on failed drag.
//This is the original XY coordinates of the draggable element.
,getRepairXY: function() {
return this.dragData.repairXY;
}
});

// This is the target when columns are dropped onto the toolbar (ie added to the group)
this.dropTarget2s = new Ext.dd.DropTarget(this.getTopToolbar().getEl(), {
ddGroup: "gridHeader" + this.getGridEl().id
,panel:this
,notifyDrop: function(dd, e, data) {
//console.debug ("Adding Filter", data);
var btname= this.panel.getColumnModel().getDataIndex( this.panel.getView().getCellIndex(data.header));
this.panel.store.groupBy(btname);
this.panel.view.fireEvent('groupchange', this, btname);
return true;
}
});

// This is the target when columns are dropped onto the grid (ie removed from the group)
this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
ddGroup: "grid-body" + this.getGridEl().id //FIXME - does this need to be unique to support multiple independant panels on the same page
,panel:this
,notifyDrop: function(dd, e, data) {
var txt = Ext.get(data.btn).dom.innerHTML;
var tb = this.panel.getTopToolbar();
//console.debug ("Removing Filter", txt);
var bidx = tb.items.findIndexBy(function(b) {
////console.debug ("Match button ",b.text);
return b.text==txt;
},this);
//console.debug ("Found matching button", bidx);
if(bidx<0) return; // Error!
var fld = tb.items.get(bidx).fieldName;
// Remove from toolbar
Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
if(bidx > 0) Ext.removeNode(Ext.getDom(tb.items.get(bidx-1).id));;

//console.debug ("Remove button", fld);
var cidx = this.panel.view.cm.findColumnIndex(fld);

if(cidx <0)
console.error("Can't find column for field ", fld);

this.panel.view.cm.setHidden(cidx, false);

// Remove this group from the groupField array
// @todo - replace with method on store
var temp=[];
for(var i = this.panel.store.groupField.length -1; i >= 0; i--) {
if(this.panel.store.groupField[i] == fld) {
this.panel.store.groupField.pop();
this.panel.view.fireEvent('groupchange', this, fld);
break;
}
temp.push(this.panel.store.groupField[i]);
this.panel.store.groupField.pop();
}

for(var i=temp.length-1;i>=0;i--) {
this.panel.store.groupField.push(temp[i]);
}

if(this.panel.store.groupField.length == 0)
this.panel.store.groupField = false;
//this.panel.view.fireEvent('groupchange', this, txt);
this.panel.store.fireEvent('datachanged', this);
return true;
}
});
}
});



MultiGroupingView: Now has the EventGroupingView and the MultiGroupingView in it.




Ext.grid.EventGroupingView = function(config) {
Ext.apply(this, config);
this.addEvents({
groupchange: true
});
Ext.grid.EventGroupingView.superclass.constructor.call(this);
};

Ext.extend(Ext.grid.EventGroupingView, Ext.grid.GroupingView, {
onGroupByClick : function(){
//console.debug ('EventGroupingView ');
this.grid.store.groupBy(this.cm.getDataIndex(this.hdCtxIndex));
this.fireEvent("groupchange", this, this.cm.getDataIndex(this.hdCtxIndex)) ;
},

onShowGroupsClick : function(mi, checked){
if(checked){
this.onGroupByClick();
}else{
this.grid.store.clearGrouping();
this.fireEvent("groupchange", this, null) ;
}
}
});

Ext.namespace("Ext.ux.grid");

Ext.ux.grid.MultiGroupingView = Ext.extend(Ext.grid.EventGroupingView, {
constructor: function(config){
Ext.ux.grid.MultiGroupingView.superclass.constructor.apply(this, arguments);
// Added so we can clear cached rows each time the view is refreshed
this.on("beforerefresh", function() {
////console.debug ("Cleared Row Cache");
if(this.rowsCache) delete rowsCache;
}, this);
this.fireEvent('groupchange', this, null);
}

,displayEmptyFields: false

,displayFieldSeperator: ', '

,renderRows: function(){
//alert('renderRows');
var groupField = this.getGroupField();
var eg = !!groupField;
// if they turned off grouping and the last grouped field is hidden
if (this.hideGroupedColumn) {
var colIndexes = [];
for (var i = 0, len = groupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(groupField[i]);
if(cidx >= 0)
colIndexes.push(cidx);
//else
//console.debug ("Ignore unknown column : ",groupField[i]);
}
if (!eg && this.lastGroupField !== undefined) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if(cidx >= 0)
this.cm.setHidden(cidx, false);
// else
//console.debug ("Error unhiding column "+cidx);
}
delete this.lastGroupField;
delete this.lgflen;
}

else if (eg && colIndexes.length > 0 && this.lastGroupField === undefined) {
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
}

else if (eg && this.lastGroupField !== undefined && (groupField !== this.lastGroupField || this.lgflen != this.lastGroupField.length)) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if(cidx >= 0)
this.cm.setHidden(cidx, false);
//else
//console.debug ("Error unhiding column "+cidx);
}
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
}
}
return Ext.ux.grid.MultiGroupingView.superclass.renderRows.apply(this, arguments);
}



/** This sets up the toolbar for the grid based on what is grouped
* It also iterates over all the rows and figures out where each group should appeaer
* The store at this point is already stored based on the groups.
*/
,doRender: function(cs, rs, ds, startRow, colCount, stripe){
////console.debug ("doRender: ",cs, rs, ds, startRow, colCount, stripe);
var ss = this.grid.getTopToolbar();
if (rs.length < 1) {
return '';
}

var groupField = this.getGroupField();
var gfLen = 0;
if (groupField != undefined){
gfLen = groupField.length;
}
////console.debug ("groupField.length " + gfLen);

// Remove all entries already in the toolbar
for (var hh = 0; hh < ss.items.length; hh++) {
Ext.removeNode(Ext.getDom(ss.items.itemAt(hh).id));
}

if(gfLen == 0) {
ss.addItem(new Ext.Toolbar.TextItem("Drop Columns Here To Group"));
//console.debug ("No Groups");
} else {
//console.debug (gfLen," Groups");

// Add back all entries to toolbar from GroupField[]
ss.addItem(new Ext.Toolbar.TextItem("Grouped By:"));
for (var gfi = 0; gfi < gfLen; gfi++) {
var t = groupField[gfi];
if(gfi>0)
ss.addItem(new Ext.Toolbar.Separator());
var b = new Ext.Toolbar.Button({
text: this.cm.getColumnHeader(this.cm.findColumnIndex(t))
});
b.fieldName = t;
ss.addItem(b);
//console.debug ("Added Group to Toolbar :",this,t,'=',b.text);
}
}

this.enableGrouping = !!groupField;

if (!this.enableGrouping || this.isUpdating) {
return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments);
}

var gstyle = 'width:' + this.getTotalWidth() + ';';
var gidPrefix = this.grid.getGridEl().id;
var groups = [], curGroup, i, len, gid;
var lastvalues = [];
var added = 0;
var currGroups = [];

// Create a specific style to indent rows
//@TODO come up with a better way to do this with a dummy column
/*
var st = Ext.get(gidPrefix+"-style");
if(st) st.remove();
Ext.getDoc().child("head").createChild({
tag:'style',
id:gidPrefix+"-style",
html:"div#"+gidPrefix+" div.x-grid3-row {padding-left:"+(gfLen*12)+"px}"+
"div#"+gidPrefix+" div.x-grid3-header {padding-left:"+(gfLen*12)+"px}"
});
*/

// Loop through all rows in srecord set
for (var i = 0, len = rs.length; i < len; i++) {
added = 0;
var rowIndex = startRow + i;
var r = rs[i];
var differ = 0;
var gvalue = [];
var fieldName;
var fieldLabel;
var grpFieldNames = [];
var grpFieldLabels = [];
var v;
var changed = 0;
var addGroup = [];

for (var j = 0; j < gfLen; j++) {
fieldName = groupField[j];
fieldLabel = this.cm.getColumnHeader(this.cm.findColumnIndex(fieldName));
v = r.data[fieldName];
if (v) {
if (i == 0) {
// First record always starts a new group
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
lastvalues[j] = v;
} else {
if ( (typeof(v)=="object" && (lastvalues[j].toString() != v.toString()) ) || (typeof(v)!="object" && (lastvalues[j] != v) ) ) {
// This record is not in same group as previous one
////console.debug ("Row ",i," added group. Values differ: prev=",lastvalues[j]," curr=",v);
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
lastvalues[j] = v;
changed = 1;
} else {
if (gfLen-1 == j && changed != 1) {
// This row is in all the same groups to the previous group
curGroup.rs.push(r);
////console.debug ("Row ",i," added to current group");
} else if (changed == 1) {
// This group has changed because an earlier group changed.
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:v});
////console.debug ("Row ",i," added group. Higher level group change");
} else if(j<gfLen-1) {
// This is a parent group, and this record is part of this parent so add it
if(currGroups[fieldName])
currGroups[fieldName].rs.push(r);
//else
// console.error("Missing on row ",i," current group for ",fieldName);
}
}
}
} else {
if (this.displayEmptyFields) {
addGroup.push({idx:j,dataIndex:fieldName,header:fieldLabel,value:this.emptyGroupText||'(none)'});
}
}
}//for j
//if(addGroup.length>0) //console.debug ("Added groups for row=",i,", Groups=",addGroup);

for (var k = 0; k < addGroup.length; k++) {
var grp=addGroup[k];
gid = gidPrefix + '-gp-' + grp.dataIndex + '-' + Ext.util.Format.htmlEncode(grp.value);

// if state is defined use it, however state is in terms of expanded
// so negate it, otherwise use the default.
var isCollapsed = typeof this.state[gid] !== 'undefined' ? !this.state[gid] : this.startCollapsed;
var gcls = isCollapsed ? 'x-grid-group-collapsed' : '';
var rndr = this.cm.config[this.cm.findColumnIndex(grp.dataIndex)].renderer;
curGroup = {
group: rndr?rndr(grp.value):grp.value
,groupName: grp.dataIndex
,gvalue: grp.value
,text: grp.header
,groupId: gid
,startRow: rowIndex
,rs: [r]
,cls: gcls
,style: gstyle + 'padding-left:' + (grp.idx * 12) + 'px;'
};
currGroups[grp.dataIndex] = curGroup;
groups.push(curGroup);

r._groupId = gid; // Associate this row to a group
}//for k
}//for i

var buf = [];
var toEnd = 0;
for (var ilen = 0, len = groups.length; ilen < len; ilen++) {
toEnd++;
var g = groups[ilen];
var leaf = g.groupName == groupField[gfLen - 1]
this.doGroupStart(buf, g, cs, ds, colCount);
if (g.rs.length != 0 && leaf)
buf = Ext.grid.GroupingView.superclass.doRender.call(this, cs, g.rs, ds, g.startRow, colCount, stripe);

if (leaf) {
var jj;
var gg = groups[ilen + 1];
if (gg != null) {
for (jj = 0; jj < groupField.length; jj++) {
if (gg.groupName == groupField[jj])
break;
}
toEnd = groupField.length - jj;
}
for (var k = 0; k < toEnd; k++) {
this.doGroupEnd(buf, g, cs, ds, colCount);
}
toEnd = jj;
}
}
return buf.join('');
}



/** Should return an array of all elements that represent a row, it should bypass
* all grouping sections
*/
,getRows: function(){

// This function is called may times, so use a cache if it is available
if(this.rowsCache)
r = this.rowsCache.slice(0);
else {
//alert('getRows');
if (!this.enableGrouping) {
return Ext.grid.GroupingView.superclass.getRows.call(this);
}
var groupField = this.getGroupField();
var r = [];
var g, gs = this.getGroups();
// this.getGroups() contains an array of DIVS for the top level groups
////console.debug ("Get Rows", groupField, gs);

r = this.getRowsFromGroup(r, gs, groupField[groupField.length - 1]);

// Clone the array, but not the objects in it
//@TODO uncomment this for caching to work
this.rowsCache = r.slice(0);
}
////console.debug ("Found ", r.length, " rows");
return r;
}


/** Return array of records under a given group
* @param r Record array to append to in the returned object
* @param gs Grouping Sections, an array of DIV element that represent a set of grouped records
* @param lsField The name of the grouping section we want to count
*/
,getRowsFromGroup: function(r, gs, lsField){
var rx = new RegExp(".*-gp-"+lsField+"-.*");

// Loop over each section
for (var i = 0, len = gs.length; i < len; i++) {

// Get group name for this section
var groupName = gs[i].id;
if(rx.test(groupName)) {
////console.debug (groupName, " matched ", lsField);
g = gs[i].childNodes[1].childNodes;
for (var j = 0, jlen = g.length; j < jlen; j++) {
r[r.length] = g[j];
}
////console.debug ("Found " + g.length + " rows for group " + lsField);
} else {
if(!gs[i].childNodes[1]) {
console.error("Can't get rowcount for field ",lsField," from ",gs,i);
} else
// if its an interim level, each group needs to be traversed as well
r = this.getRowsFromGroup(r, gs[i].childNodes[1].childNodes, lsField);
}
}
return r;
}
});



MultiGroupingStore: still the same but with some (little) modifications to work with the Dynamic stuff.




Ext.namespace("Ext.ux.grid");

Ext.ux.grid.MultiGroupingStore = Ext.extend(Ext.data.GroupingStore, {

constructor: function(config){
Ext.ux.grid.MultiGroupingStore.superclass.constructor.apply(this, arguments);
}

,sortInfo: []

,sort: function(field, dir){
//console.debug ('sort '+ field);
var f = [];
if (Ext.isArray(field)) {
for (var i = 0, len = field.length; i < len; ++i) {
f.push(this.fields.get(field[i]));
}
} else {
f.push(this.fields.get(field));
}

if (f.length < 1) {
return false;
}

if (!dir) {
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].field == f[0].name) { // toggle sort dir
dir = (this.sortToggle[f[0].name] || "ASC").toggle("ASC", "DESC");
} else {
dir = f[0].sortDir;
}
}

var st = (this.sortToggle) ? this.sortToggle[f[0].name] : null;
var si = (this.sortInfo) ? this.sortInfo : null;

this.sortToggle[f[0].name] = dir;
this.sortInfo = [];
for (var i = 0, len = f.length; i < len; ++i) {
this.sortInfo.push({
field: f[i].name,
direction: dir
});
}

if (!this.remoteSort) {
this.applySort();
this.fireEvent("datachanged", this);
} else {
if (!this.load(this.lastOptions)) {
if (st) {
this.sortToggle[f[0].name] = st;
}
if (si) {
this.sortInfo = si;
}
}
}

}

,setDefaultSort: function(field, dir){
dir = dir ? dir.toUpperCase() : "ASC";
this.sortInfo = [];
//console.debug ('setDefaultSort '+ field);
if (!Ext.isArray(field))
this.sortInfo.push({
field: field,
direction: dir
});
else {
if(field != undefined){
for (var i = 0, len = field.length; i < len; ++i) {
this.sortInfo.push({
field: field[i].field,
direction: dir
});
this.sortToggle[field[i]] = dir;
}
}
}
}

// @todo: if field passed in is an array, assume this is a complete replacement for the 'groupField'
// @todo: if field passed in is empty/null, assume this means group by nothing, ie remove all groups
,groupBy: function(field, forceRegroup){
// alert("groupBy " + field + " " + forceRegroup);
if (!forceRegroup && this.groupField == field) {
return; // already grouped by this field
}

//if field passed in is an array, assume this is a complete replacement for the 'groupField'
if(Ext.isArray(field)) {
if(field.length==0)
// @todo: field passed in is empty/null, assume this means group by nothing, ie remove all groups
this.groupField=false;
else
this.groupField=field;
} else {
// Add the field passed as as an additional group
if (this.groupField) {
// If there is already some grouping, make sure this field is not already in here
if(this.groupField.indexOf(field)==-1)
this.groupField.push(field);
else
return; // Already grouped by this field
} else
// If there is no grouping already use this field
this.groupField = [field];
}
if (this.remoteGroup) {
if (!this.baseParams) {
this.baseParams = {};
}
this.baseParams['groupBy'] = field;
}
if (this.groupOnSort) {
this.sort(field);
return;
}
if (this.remoteGroup) {
this.reload();
}
else {
var si = this.sortInfo || [];
if (si.field != field) {
this.applySort();
}
else {
// alert(field);
this.sortData(field);
}
this.fireEvent('datachanged', this);
}
}

,applySort: function(){
//console.debug ('applySort ');

var si = this.sortInfo;
////console.debug ('sortInfo ' + si);
if (si && si.length > 0 && !this.remoteSort) {
this.sortData(si, si[0].direction);
}

if (!this.groupOnSort && !this.remoteGroup) {
var gs = this.getGroupState();
if (gs && gs != this.sortInfo) {
this.sortData(this.groupField);
}
}
}

,getGroupState: function(){
////console.debug ('getGroupState '+ this.groupField);
return this.groupOnSort && this.groupField !== false ? (this.sortInfo ? this.sortInfo : undefined) : this.groupField;
}

,sortData: function(flist, direction) {
////console.debug ('flist '+ flist);
//console.debug ('sortData direction '+ direction);
direction = direction || 'ASC';
var st = [];
var o;
////console.debug ('this.fields '+ this.fields.get('ir_no'));
if(this.fields.get('ir_no') != undefined){
for (var i = 0, len = flist.length; i < len; ++i) {
o = flist[i];
////console.debug ('pushing '+ o.field);
st.push(this.fields.get(o.field ? o.field : o).sortType);
}
}
var fn = function(r1, r2){
var v1 = [];
var v2 = [];
var len = flist.length;
var o;
var name;
var result;
////console.debug ('sorting ');
for (var i = 0; i < len; ++i) {
o = flist[i];
name = o.field ? o.field : o;
////console.debug ('st[i] ' + st[i]);
if(st[i] != undefined){
v1.push(st[i](r1.data[name]));
v2.push(st[i](r2.data[name]));
}
}

for (var i = 0; i < len; ++i) {
result = v1[i] > v2[i] ? 1 : (v1[i] < v2[i] ? -1 : 0);
////console.debug ('result '+ result);
if (result != 0)
return result;
}
return result; //if it gets here, that means all fields are equal
}; //end fn

this.data.sort(direction, fn);
if (this.snapshot && this.snapshot != this.data) {
////console.debug ('snapshot ');
this.snapshot.sort(direction, fn);
}

} //end

,removeGroupField: function(fld) {
// @todo
if(this.groupField) {
var i = this.groupField.length;
this.groupField.remove(fld);
// See if anything was really removed?
if(this.groupField.length < i) {
if(this.groupField.length == 0)
this.groupField = false;
// Fire event so grid can be re-drawn
this.fireEvent('datachanged', this);
}
}
}
});




Now to put it together.




viewds = new Ext.ux.grid.MultiGroupingStore({
proxy: new Ext.data.HttpProxy({url:'http://' + document.domain + '/lib/vbscript/viewBuilderPage.asp' ,nocache:true, success: displayView, method:'POST'}),
reader: new Ext.data.DynamicXmlReader({
record: 'row',
totalRecords: 'totalRecords',
recordDefinition: 'recordDefinition'
})
});

grouping = new Ext.ux.grid.MultiGroupingView({
groupField: false,
displayEmptyFields: true,
startCollapsed : true,
groupTextTpl: '{text} : {group} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})',
displayFieldSeperator: ', '
});


viewgrid = new Ext.ux.grid.MultiGroupingPanel({
renderTo: 'view-south-grid',
store: viewds,
statefull: false,
trackMouseOver : true,
bbar: pagingtb,
enableColumnMove: false,
resizable : true,
sortable: true,
bodyBorder : false,
monitorWindowResize : true,
autoScroll: true,
view: grouping,
listeners: {
//rowIndex not working
[B]rowdblclick : function(grid, rowIndex, e) {
var gridrecord = grid.getStore().getAt(rowIndex);
if(gridrecord != undefined){
trackingnumber = gridrecord.get('ir_no');
Ext.MainLayout.showDefect(trackingnumber);
}
} //end rowdblclick
}
});




It would really be great if someone could get the rowIndex to work for me. I really need it.

I hope you can all use this. This Mult-Grouping Grid Extension was just the thing we really needed. Thank you All for the hard work you have put in to make this happen.

galdaka
11 Sep 2008, 5:48 AM
Thanks!!

Is posible put all in zip file with live example for upload to my website www.jadacosta.es (http://www.jadacosta.es) (For test pourposes)?

Greetings,

ljkmchale
11 Sep 2008, 9:16 AM
Not really;

The project that I am using this in is very large. I can put the code I have given in a zip file but it will be the same code I posted.

galdaka
11 Sep 2008, 11:05 AM
Not really;

Sorry for my English,

The project that I am using this in is very large. I can put the code I have given in a zip file but it will be the same code I posted.

The best way for the community Ext try and test your code test is to put an live example or an example that can be easily drag and drop in the folder examples of Ext core distribution.

I recommend you add a static example because the example that you attach a code calling ASP server does not seem very helpful.

Thanks in advance,

ljkmchale
12 Sep 2008, 4:08 AM
Why would you need to try and test my code? The original code Mult-Grouping Grid Extension is having the rowindex problem. I cant seem to get the original code to work. My code just carries over the problem. :)

Here is the replacement to the multigroup.js file from the original code. I added a listener (in bold) to deminstrate the issue with the rowindex.



Array.prototype.sum = function(field){
if(field)
for(var i=0,sum=0;i<this.length;sum+=parseFloat(this[i++].data[field]));
else
for(var i=0,sum=0;i<this.length;sum+=this[i++]);
return sum;
}

Ext.onReady(function(){
Ext.QuickTips.init();

var WorkOrderRecord = Ext.data.Record.create([
{name: 'workOrderNo'}
,{name: 'contract'}
,{name: 'segregationCode'}
,{name: 'topWorkOrderNo'}
,{name: 'part'}
,{name: 'serial'}
,{name: 'span'}
,{name: 'ecd', type:'date'}
,{name: 'laborHours'}
,{name: 'materialCosts'}
]);

var columnModel = new Ext.grid.ColumnModel([{
header: 'Contract No'
,width: 100
,dataIndex: 'contract'
}, {
header: 'Segregation Code'
,width: 100
,dataIndex: 'segregationCode'
}, {
header: 'Top Work Order'
,width: 100
,dataIndex: 'topWorkOrderNo'
}, {
header: 'Work Order'
,width: 100
,dataIndex: 'workOrderNo'
}, {
header: 'Part'
,width: 100
,dataIndex: 'part'
}, {
header: 'Serial'
,width: 100
,dataIndex: 'serial'
,sortable: true
}, {
header: 'Span'
,width: 100
,dataIndex: 'span'
,align: 'right'
}, {
header: 'ECD'
,width: 100
,dataIndex: 'ecd'
,renderer: Ext.util.Format.dateRenderer()
}, {
header: 'Labor Hours'
,width: 100
,dataIndex: 'laborHours'
,align: 'right'
}, {
header: 'Material Costs'
,width: 100
,dataIndex: 'materialCosts'
,align: 'right'
}
]);


// create reader that reads into Topic records
var reader = new Ext.data.JsonReader({
totalProperty: 'total'
,root: 'rows'
,id: 'workOrderNo'
}, WorkOrderRecord);

var groupStore = new Ext.ux.grid.MultiGroupingStore({
proxy: new Ext.data.HttpProxy({
url: 'orders.json',
method: 'GET'
})
,reader: reader
,sortInfo: {field: 'workOrderNo', direction: 'ASC'}
,groupField: ['contract','part','topWorkOrderNo']
});

var groupView = new Ext.ux.grid.MultiGroupingView({
hideGroupedColumn :true
,emptyGroupText: 'All Group Fields Empty'
,displayEmptyFields: true //you can choose to show the group fields, even when they have no values
,groupTextTpl: '{text} : {group} ({[values.rs.length]} {[values.rs.length == 1 ? "Record" : "Records"]}) / Total Material Cost={[fm.usMoney(values.rs.sum("materialCosts"))]}'
,displayFieldSeperator: ', ' //you can control how the display fields are seperated
});

var grid = new Ext.ux.grid.MultiGroupingPanel({
store: groupStore
,cm:columnModel
,view: groupView
,width: 1024
,height: 400
,collapsible: true
,animCollapse: true
,title: 'Grouping Example'
,iconCls: 'icon-grid'
,renderTo: 'multiGroupEx1'
,listeners: {
rowdblclick : function(grid, rowIndex, e) {
console.debug ("rowdblclick: " + rowIndex);
} //end rowdblclick
}
,bbar: [
{
text:"Clear All"
,scope:groupStore
,handler: function() {
console.debug("This=",this);
this.groupBy([]);
}
},'-',{
text:"Remove Contract"
,scope:groupStore
,handler: function() {
this.removeGroupField('contract');
}
},'-',{
text:"Set to ECD"
,scope:groupStore
,handler: function() {
this.groupBy(['ecd']);
}
},'-',{
text:"Set To Contract, Work Order"
,scope:groupStore
,handler: function() {
this.groupBy(['contract','topWorkOrderNo']);
}
}
]
});

groupStore.load();

});

galdaka
12 Sep 2008, 4:18 AM
Why would you need to try and test my code? The original code Mult-Grouping Grid Extension is having the rowindex problem. I cant seem to get the original code to work. My code just carries over the problem. :)

Ah ok. I understand that your extension adds nothing to the original. Is it true?

If this is true and do not want to test your code does not understand what is the pourpose of your post.

If this is false live demo will be helpful.

Thanks in advance,

ljkmchale
12 Sep 2008, 4:36 AM
My extension does add to the original but the rowindex is inherited from the original code. I added the code to my last post. If you download the original code and replace the js file you will see the problem I am having with the rowIndex.

ljkmchale
12 Sep 2008, 5:51 AM
As I work more to solve this problem. I have discovered that none of the events that use rowIndex is working. What I mean is that any event that passes rowIndex does fire but rowIndex is undefined in all of them. Any clues?:((

Jack_S
16 Sep 2008, 10:57 AM
Hello,

I'm in great need of this extension, and was curious to know if there will be an official stable version or whether I need to get the JS files, and apply all the fixes posted along this thread. Or is there a republished of this extension available for the community to use.

Also the base JS files mentioned are in fact the ones found here : ?

http://extjs.com/forum/showthread.php?t=42454&page=3

Thanks

Jack

galdaka
16 Sep 2008, 11:32 AM
Hello,

I'm in great need of this extension, and was curious to know if there will be an official stable version or whether I need to get the JS files, and apply all the fixes posted along this thread. Or is there a republished of this extension available for the community to use.

Also the base JS files mentioned are in fact the ones found here : ?

http://extjs.com/forum/showthread.php?t=42454&page=3

Thanks

Jack

I think that the last version is in: http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

Greetings,

Jack_S
16 Sep 2008, 10:09 PM
Hello,

I've visited the aforementioend example link, but how to I download the two referenced file.



<!--<script type="text/javascript" src="tool-bar.js"></script>-->
<script type="text/javascript" src="ux/MultiGrouping.js"></script>
<script type="text/javascript" src="ux/Multi.js"></script>


Thanks

Jan

galdaka
16 Sep 2008, 10:20 PM
Hello,

I've visited the aforementioend example link, but how to I download the two referenced file.



<!--<script type="text/javascript" src="tool-bar.js"></script>-->
<script type="text/javascript" src="ux/MultiGrouping.js"></script>
<script type="text/javascript" src="ux/Multi.js"></script>


Thanks

Jan

I attach ZIP file with last example.

Greetings,

ljkmchale
17 Sep 2008, 8:40 AM
galdaka, your a genius. Thank you for solving the rowIndex and mouseover issues. :))
I have the new code now for the Dynamic grid plus this.

mcouillard
22 Sep 2008, 10:03 AM
I attach ZIP file with last example.

Thanks galdaka! I just upgraded from Paule's example back on page 1. It worked very well.

galdaka
22 Sep 2008, 11:01 AM
I final got time to clean up my code, and I've posted it to the jaffa sourceforge project and deploy a working version for you all to see. Here is the link http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html

I have included links to all the relevant code in CVS, as well as a change log, and details of which issues mentioned on this thread that have been fixed (thanks for the input)

I have put this code under an LGPL, even though ExtJS is under a GPL. Hope that works for all.

I will continue to work through the other issues on the list as time permits

PaulE

Any advance?

Thanks,

Jack_S
26 Sep 2008, 3:08 AM
Hello All,

I've managed to configure the multi-grouping grid but cannot get it 100% operational. I'm running into the following error:



this.cm.lookup[this.cm.findColumnIndex(t)] has no properties
[Break on this error] text: this.cm.lookup[this.cm.findColumnIndex(t)].header


I was wondering if anything comes to mind.

Thanks

Jack

Jack_S
26 Sep 2008, 4:58 AM
This error actually stems for either a missing column or a bad mapping between a column and dataIndex (Check spelling mistakes)

Jack_S
26 Sep 2008, 2:56 PM
Hello,

I'm not sure if I may not have post my following thread on the wrong forum. Is this a bug, or am I doing something wrong. Been troubleshooting it for hours, but with no error messages from firebug, I have no more ideas where to search for the problem.

http://extjs.com/forum/showthread.php?t=48378

Thanks for any help in this matter.

Jack

ut_paule
26 Sep 2008, 5:08 PM
Any advance?

Thanks,

Yes, i've just checked in a new version, have not had time to host it yet, but it fixes many issues and there is also a live paging example that loads in 20 rows at a time and give an indication if a group has not been completely loaded.

The code is all in CVS with examples, but you will need a JSP container to show the live paging stuff (unless someone wants to re-write the JSP to be PHP or Perl i won't be able to host this as a working example on sourceforge :( )

I'll be posting back here soon with more details on all the changes and fixes.

Base Code http://jaffa.cvs.sourceforge.net/jaffa/JaffaRIA/source/html/js/extjs/ux/grid/
Examples http://jaffa.cvs.sourceforge.net/jaffa/JaffaRIA/source/html/tests/extjs/multigroup/

Enjoy.

PaulE

Jack_S
27 Sep 2008, 8:38 AM
Hello,

I was curious to know what was the recommended version to have this extension working correctly.

I've tried evertyhing I know and the only thing that comes to mind is that I'm using version 2.0. rather then 2.2?

Otherwise, I'm clueless why I only see one item...

Thanks

Jack

ut_paule
30 Sep 2008, 5:11 PM
As I work more to solve this problem. I have discovered that none of the events that use rowIndex is working. What I mean is that any event that passes rowIndex does fire but rowIndex is undefined in all of them. Any clues?:((

Yes, there was a bug in caching the value in the MuiltGroupingView.getRows() method in the viewer. If you comment out the this.rowsCache=r; this should fix it

ut_paule
30 Sep 2008, 5:15 PM
I have noticed a couple of things that are no longer working. I am comparing this new grid (which is fantastic) to the standard grouping grid.

3. The little sort arrow no longer appears at any time.

Any clues, or is it just me? :)

I this this is because this.sortInfo is now returning a array, in the original GroupingStore this was and object. The default Grid renderer assumes that this.sortInfo.field would be the field name, and this is now this.sortInfo[0].field

I'll be looking into this later to factor in a fix, but i think that this is the cause.

pbuyle
3 Oct 2008, 1:29 AM
Hi,

First, thank you for sharing you code as I was going to start coding the same features from scratch. I hope I'll be able to re-use your code and to share back.

In the constructor for Ext.ux.grid.MultiGroupingPagingGrid (from http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html), the bottom toolbar is retrieved through getBottomToolbar. But getBottomToolbar can only be used to retrieve the toolbar after render (see bbar documentation in Ext.Panel). Thus, the class is currently not usable for lazy rendering.

To fix this, it should be enough to move bottom toolbar items retrieval and event handlers registration to the (overrided) onRender method (which is already registred as 'render' event handler).

Also, in the constructor, the first line create a new config Object if needed (config = config||{}). But when superclass constructor is called, the original arguments array-like is used. If config was originaly undefined, arguments does not contains the newly created one. The easiest is probably to ignore the orginal arguments when calling the superclass' constructor.

Here is the my code with the proposed changes applied


Ext.ux.grid.MultiGroupingPagingGrid = Ext.extend(Ext.ux.grid.MultiGroupingPanel, {

/** When creating the store, register an internal callback for post load processing
*/
constructor: function(config) {
config = config||{};
config.bbar = [].concat(config.bbar);
config.bbar = config.bbar.concat([
' '
,'-'
,{xtype:'tbtext',id:'counter',disabled: false,text: '? of ?'}
,{xtype:'tbbutton',id:'more',text: 'More...',handler: function() { this.store.loadMore(false); }, scope: this}
,{xtype:'tbbutton',id:'loading',hidden: true,iconCls: "x-tbar-loading"}
]);

Ext.ux.grid.MultiGroupingPagingGrid.superclass.constructor.apply(this, [config]);

// As the default onLoad to refocus on the first row has been disabled,
// This has been added so if a load does happen, and its an initial load
// it refocuses. If this is a refresh caused by a sort/group or a new page
// of data being loaded, it does not refocus
this.store.on("load", function(r,o) {
if(o&&o.initial==true)
Ext.ux.grid.MultiGroupingView.superclass.onLoad.call(this);
}, this.view);

// Create Event that asks for more data when we scroll to the end
this.on("bodyscroll", function() {
var s = this.view.scroller.dom;
if( (s.offsetHeight+s.scrollTop+5 > s.scrollHeight) && !this.isLoading) {
console.debug("Grid.bodyscroll.Event: Get more...");
this.store.loadMore(false);
}
}, this);
},

onRender: function()
{
Ext.ux.grid.MultiGroupingPagingGrid.superclass.onRender.apply(this, arguments);

// Extend the bottom toolbar, for record paging info
console.debug("bb=",this.getBottomToolbar());
var bb=this.getBottomToolbar();
this.barCounter = bb.items.itemAt(bb.items.length-3);
this.barMore = bb.items.itemAt(bb.items.length-2);
this.barLoading = bb.items.itemAt(bb.items.length-1);

// When the grid start loading, display a loading icon
this.store.on("beforeload", function(o) {
if(this.isLoading) {
//console.debug("Store.beforeload.Event: Reject Load, on is in progress");
return false;
}
this.isLoading = true;
this.barLoading.setVisible(true);
console.debug("Store.beforeload.Event: options=",o, this);
return true;
}, this);

// When loading has finished, disable the loading icon, and update the row count
this.store.on("load", function() {
delete this.isLoading;
this.barLoading.setVisible(false);
//console.debug("Store.load.Event: Finished loading",this.barCounter.getEl());
this.barCounter.getEl().innerHTML = "Showing " + this.store.getCount()+' of ' +
(this.store.totalCount?this.store.totalCount:'?');
if(this.store.totalCount) this.barMore.disable();
return true;
}, this);
// When a loading error occurs, disable the loading icon and display error
this.store.on("loadexception", function(e) {
console.debug("Store.loadexception.Event:",arguments);
delete this.isLoading;
this.barLoading.setVisible(false);
Ext.Message("Error Loading Records - " + e);
return false;
}, this);
}
});

pbuyle
3 Oct 2008, 3:45 AM
Here is another change proposition.

Ext.ux.grid.MultiGroupingPagingStore override the load method it can merge the groupFields and sortField into a single sort criteria (group fields need to be sorted by first!). Tt merges groupdField and sortInfo in a single comma (',') separated list. In this list, sortInfo elements are turned into strings like ${field} ${direction}. Depending on your server-side technology, it not necessary the best format or the format you wan. It may be useful to ease the customization of the merging of groupFields and sortField and the resulting query parameter. Here is the required change


Ext.ux.grid.MultiGroupingPagingStore = Ext.extend(Ext.ux.grid.MultiGroupingStore, {

//...

/**
* Override the load method so it can merge the groupFields and sortField
* into a single sort criteria (group fields need to be sorted by first!)
*/
,load : function(options){
options = options || {};
if(this.fireEvent("beforeload", this, options) !== false){
this.storeOptions(options);
var p = Ext.apply(options.params || {}, this.baseParams);
p[this.paramNames.sort]= this.buildSortParameter();
this.proxy.load(p, this.reader, this.loadRecords, this, options);
return true;
} else {
return false;
}
}

/**
* Build and returns a query 'sort' parameter. Provided as an independant
* method so that it can be replaced with another implementation (using
* {@link Ext.override}, subclassing, etc.).
*
* @return {String} A query 'sort' parameter.
*/
,buildSortParameter: function()
{
var sort=[];
if(this.groupField && this.remoteGroup){
if(Ext.isArray(this.groupField))
sort[sort.length] = this.groupField.join(",");
else
sort[sort.length] = this.groupField;
}
if(this.sortInfo && this.remoteSort){
if(Ext.isArray(this.sortInfo))
for(var i=0;i<this.sortInfo.length;i++)
sort[sort.length]=this.sortInfo[i].field + " " + this.sortInfo[i].direction;
else
sort[sort.length]=this.sortInfo.field + " " + this.sortInfo.direction;
}
return sort.join(',');
}

//...

}
and here is a sample alternative implementation that send the merged groupField(s) and sortInfo(s) as a single array (automagically serialized in JSON by Ext). Plugged through Ext.override


Ext.override(Ext.ux.grid.MultiGroupingPagingStore, {
buildSortParameter: function() {
var sort=[];
if(this.groupField && this.remoteGroup) {
Ext.each(this.groupField, function(groupField){
sort[sort.length] = {field: groupField};
});
}
if(this.sortInfo && this.remoteSort) {
Ext.each(this.sortInfo, function(sortInfo) {
if(sortInfo.field)
sort[sort.length] = this.sortInfo;
});
}
return Ext.encode(sort);
}
});

smarttdv
3 Oct 2008, 5:41 PM
PaulE,

First of all, I would like to thank you for this extension. It will save me a lot of time. :) I tested out your new version and it seemed to work well except the pop-up (RowSelectionModel). After I clicked on a child row, a popped up window showed message "You have selected..." However, when I select any button in the bottom bar or any column header, the message with the last id still showed. How can I get rid of it?

Another question, if I want to display the grouping in one row instead of multiple rows (tree like your example), how can I do that? For example,

Contract No : CX123 - Part : ABCD (4 Records)
-record1
-record2
-record3
-record4
Contract No : CX123 - Part : ABCDE (1 Record)
-record1

Thank you in advance for your hint.

Jack_S
18 Oct 2008, 1:52 PM
Hello All,

I've successfully implemented this extension into my site, and want to thank for this awesome extension.
However, I have run into a problem which I do not know how to resolve. I'm trying to implement the grouping summary.


http://extjs.com/deploy/dev/examples/grid/totals.html

I suspect that the cause is because the MultiGrouping uses a litel of GroupField, and Grouping Summary uses 1 siingle groupField to do the summary on. Is there a simple way to tell the Grouping summary to use only the last grouField ?

Thanks

Jack

galdaka
18 Oct 2008, 2:07 PM
Hello All,

I've successfully implemented this extension into my site, and want to thank for this awesome extension.
However, I have run into a problem which I do not know how to resolve. I'm trying to implement the grouping summary.


http://extjs.com/deploy/dev/examples/grid/totals.html

I suspect that the cause is because the MultiGrouping uses a litel of GroupField, and Grouping Summary uses 1 siingle groupField to do the summary on. Is there a simple way to tell the Grouping summary to use only the last grouField ?

Thanks

Jack

You have a live example?

Thanks in advance,

Jack_S
19 Oct 2008, 4:15 AM
Hello,

Sorry I do not have a live example.
A simple testing example can be performed if you change one of the columns (dummy data - MultiGrouping) to contain numeric values and then apply the GroupingSummary.

Here is quick example of how you would integrate the GroupingSummary once you have your dummy data for MultiGrouping.

--> copy the file GroupingSummary.js for the exples folder in extjs

then configure the GroupingView:



viewGroup = new Ext.ux.MultiGroupingView({
hideGroupedColumn: true
,forceFit: true
,emptyGroupText: 'All Group Fields Empty'
,enableNoGroups: false //SUMMARY
,showGroupName: false //SUMMARY
,displayEmptyFields: true
,groupTextTpl: '{text} : {gvalue}'
,displayFieldSeparator: ', '

});

configure the columnModel (col) which you want the summary on)



.
.
{
header: 'Cost (&euro;)'
,width: 100
,dataIndex: 'cost_total_eu'
,groupable: false
,sortable: false
,renderer: renderMoney
,summaryType:'sum'
,summaryRenderer: renderMoney
}]);

this.summaryPlugin = new Ext.grid.GroupSummary();


Now inside your grouping grid add the pluggin



gridGroup = new Ext.ux.MultiGroupingPanel({
id: 'gridGroup'
,store: dsGroup
,cm: getColumnModelGroup()
,view: viewGroup
,width: 1024
,height: 600
,plugins: this.summaryPlugin //SUMMARY
,renderTo: document.body
});


How ever this only works on SimpleGrouping where you group on only 1 field. This actually produces nothing in MultiGrouping, as I said I suspect its because there is more then 1 field in the groupField list. I'm not a seasoned programmer, have tried to fiddle around with this with no results.

Thanks

Jack

dbenitez
23 Oct 2008, 11:18 AM
Hey guys I ve added some fixes to the MultiGrouping.js file so you can use it along with GroupSummary.js. I took me sometime to figure out but I got it. Please let me know if you guys get any errors etc...



store = new Ext.ux.MultiGroupingStore({
reader: new Ext.data.JsonReader({
totalProperty:"recordCount",
root:"data"
},[
{name:'col1',type:'int'},
{name:'col3'},
{name:'orderid',type:'int'},
{name:'total',type:'float'}
]),
url:'/put/your/URL/',
baseParams:{},
sortInfo:{field:'col1',direction:'DESC'},
groupField:['col1','col3']
});
var myGrid = new Ext.grid.GridPanel({
ds:store,
columns:[
{header:col1, dataIndex:'col1'},
{header:'col3', dataIndex:'col3'},
{header:'OrderID', dataIndex:'orderid',summaryRenderer:function(v,o,p,g){
return "("+g.group.split(":")[1]+"):";
}},
{header:'Total', dataIndex:'total',summaryType:'sum',renderer:'usMoney'}
],
view:new Ext.ux.MultiGroupingView({
hideGroupedColumn :false,
startCollapsed:true,
forceFit: true,
emptyGroupText: 'All Group Fields Empty',
displayEmptyFields: true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Records" : "Record"]})',
displayFieldSeperator: ', '
}),
width:800,
height:500,
plugins:new Ext.grid.GroupSummary()
})

cujo13
26 Oct 2008, 5:01 PM
Does anyone know a way to collapse all groups on load?

source78
26 Oct 2008, 10:39 PM
thanks for your multigroup with multigroup summary, here I have a problem:
how to remove the display text before ':' ,just like this:

DISTRICT_ID:

cujo13
27 Oct 2008, 6:53 AM
[QUOTE=source78;243513]thanks for your multigroup with multigroup summary, here I have a problem:
how to remove the display text before ':' ,just like this:

DISTRICT_ID:

pops
6 Nov 2008, 7:37 AM
Hello,


I'm using the *excellent* MultiGrouping Grid Extension, but I encounter a small problem (unfortunately big for me).
When I group data on a column and I leave this column displayed, I can not sort by that column. I'd like to sort this column to change the order of groups.
Is it possible? I search a lot for a solution but without success (it seems to be possible on a simple grouping grid)

Thank you by advance.

Pops.

johnstontrav
11 Nov 2008, 3:29 PM
Great plugin!

I have everything working in a tab but when i close the tab I get the following error:

C[A].proxyTop is undefined

Does anyone else get this error with grouping grid within tabs? Any help would be great!

Cheers,
Trav.

wayne_o
13 Nov 2008, 5:16 AM
This plug in is great - and works well on its own - but is there any progress with the multigroup summary plugin? And has anyone got it working with the grid summary plugin?

Also - what is the latest, stable release?

Cheers

w://

tklever
14 Nov 2008, 3:53 PM
This extension is terrific, but I have a couple of issues that I can't seem to solve. I'm brand new to extJS so please excuse my novice status.

In a multi-grouped grid, is it possible to have a column that is a calculated percent of the group parent. I.E. If group A has 5 children, child one is 4 percent of total, child 2 is 55....etc, etc. This data would obviously have to dynamically change as the groupings were dynamically changed.

Can I sum the store to get a global total for the entire grid. So far storeName.sum('fieldName') has yielded me nothing. Is there a trick to it using the multiGroupedGrid?

Thanks for your help and wisdom!!

shankys_4u
17 Nov 2008, 11:59 PM
Hi Venky,Please let me know how to use Mutliple level of grouping.if possible post the code....

Thanx.....

iamdman
26 Nov 2008, 12:47 PM
Has anyone got a working version of multiple levels of grouping with summaries???

codingvista
28 Nov 2008, 1:41 AM
You should find that this works:

http://extjs.com/forum/showthread.php?p=242478#post242478

w://

codingvista
28 Nov 2008, 8:02 AM
Any one know how I can get the getRowsFromGroup method in MultiGrouping.js to use the groupId instead of the group header text?

w://

iamdman
28 Nov 2008, 11:41 AM
You should find that this works:

http://extjs.com/forum/showthread.php?p=242478#post242478

w://

Yes but I don't think this supports paging.

galdaka
2 Dec 2008, 3:16 AM
Hi,

I

codingvista
2 Dec 2008, 3:23 AM
You'll need to have this code too:

http://jaffa.cvs.sourceforge.net/viewvc/jaffa/JaffaRIA/source/html/js/extjs/ux/utils/

Be warned I'm having all sorts of issues getting the sumaries to work.

w://

galdaka
2 Dec 2008, 3:33 AM
You'll need to have this code too:

http://jaffa.cvs.sourceforge.net/viewvc/jaffa/JaffaRIA/source/html/js/extjs/ux/utils/

Be warned I'm having all sorts of issues getting the sumaries to work.

w://

Hi,

Thanks for the fast response. I add Ext.ux.clone code (Jsakalos code). But fails.

We have many versions of code (And examples in my home site: http://www.jadacosta.es/extjs/examples/multigroup2/MultiGroup.html) and I want a simple example reference with latest source code for begin to work.

I want to make multigroup with paging example.


Thanks in advance,

vicirst
12 Dec 2008, 2:28 AM
Hi,
I try to combine multigroup and autogrid with no luck,
if i put onMetaChange to Ext.ux.MultiGroupingPanel seems that event never get called,

I think combination of on-the-fly column creation with grouping ability will benefit us all.

Thanks,

galdaka
23 Dec 2008, 2:13 PM
I upload one example with fix for grouping boolean typed column without errors: http://www.jadacosta.es/extjs/examples/multigroup3/MultiGroup.html (http://www.jadacosta.es/extjs/examples/multigroup3/MultiGroup.html)

Thanks to Aurelien for this fix.



> for (var j = 0; j < gfLen; j++) {
> fieldName = groupField[j];
> fieldLabel = this.cm.lookup[this.cm.findColumnIndex(fieldName)].header;
> v = r.data[fieldName];
> if (v !== "") {
> if (i == 0) {
> // First record always starts a new group
>
> if(v !== "") tests for type match too, not just value match. Using this, one can properly group by true/false columns.

yrobla
31 Dec 2008, 8:09 AM
I've tried to download that file but it tells me that it's corrupt. I'm really interested in multigroupingsummary but i don't know how to implement it. Please anybody could upload the right file?
Thanks
Yolanda

StaticVoidMain
11 Jan 2009, 9:47 AM
Hi, first of all thanks for such a great extension but i have problems making it work in Chrome, at first i had some issues with console nothing was shown on the page, then i commented out every call to console and now the grid is shown but no data on it if i remove all the grouped fields from the bar then the data is there but no grouping, anyone else with this kind of problem?

Thanks in advance.
Jer

maquejp
12 Jan 2009, 7:29 AM
Hi,

I am interrested in this UX, Where can I find the latest stable sources?

Thank you.

tBSTAR
24 Jan 2009, 9:20 PM
Hi there,

I was wondering if I can use the groupTextTpl somehow as a footer rather than a header?
Thanks

P.S
maquejp, you can get it here: http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html
or here: http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html
btw, they come from two different sources.

wayne_o
26 Jan 2009, 2:14 AM
Nope - you need to use the MultiGroupSummary extension - as far as I know.

This is because the doGroupEnd method is implemented incrrectly.

I have a version which allows multi level grouping and multigroup summaries - I'll upload the code later today if I get the chance - it's not fully tested etc but it seems to be working for me.

w://

praveen.infra
26 Jan 2009, 7:29 AM
Hi,

im trying to use rowactions plugin with MultiGroupingGrid but it doent render the buttons. and i think everything executes fine because i never get any error messege in firebug console either?

any hints guys ?

wayne_o
26 Jan 2009, 7:32 AM
Are the references to the icons set up properly? I think that this is set up in the CSS for this plugin.

Can you get it to work on a bare minimum configuration grid?

w://

praveen.infra
26 Jan 2009, 7:43 AM
Are the references to the icons set up properly? I think that this is set up in the CSS for this plugin.

Can you get it to work on a bare minimum configuration grid?

w://
yes. it works fine on other grids. but when i apply the same thing to MultiGroupingGrid the icons stop getting rendered without giving any error..... :(

tBSTAR
26 Jan 2009, 8:39 AM
Thanks wayne_o (http://extjs.com/forum/member.php?u=2383), I am facing a problem with the GroupSummary. I don't if you can help but this is my problem: I have a column set as string so I can return multiple dollard amounts like this: 60.00~26.25. and I parse this text when I render the column.


{ header: 'Group/RC-Amt',dataIndex: 'AdjustmentMonetaryAmount',
renderer: function(v, params, record){

var str;
if(!String.IsNullOrEmpty(record.data.AdjustmentMonetaryAmount))
{
if (record.data.AdjustmentMonetaryAmount.indexOf("~")>=0)
{
var col_array = record.data.AdjustmentMonetaryAmount.split("~");
for (i=0;i<=col_array.length-1;i++)
{
col_array[i] = Ext.util.Format.usMoney(col_array[i]) + '<br/>';
}
str = col_array.join("");
}
else { str = Ext.util.Format.usMoney(record.data.AdjustmentMonetaryAmount); }
}
return str;
}, summaryType:'GrpAmt'
}
So this works, one row with multiline amount. The result is:
$60.00
$26.25
Great. But when it comes to the summary I do this:



Ext.grid.GroupSummary.Calculations['GrpAmt'] = function(v, record, field){

var sum;
if(!String.IsNullOrEmpty(record.data.AdjustmentMonetaryAmount))
{
if (record.data.AdjustmentMonetaryAmount.indexOf("~")>=0)
{
var col_array = record.data.AdjustmentMonetaryAmount.split("~");
var sum = parseFloat(col_array[0]);
for (i=1;i<=col_array.length-1;i++)
{
sum = sum + (parseFloat(col_array[i]));
}
alert(sum);
}
else { sum = record.data.AdjustmentMonetaryAmount; }
}
return Ext.util.Format.usMoney(sum.toString());
}

I tried every possible combination and I still get $Nan.00 no matter what I do. But the funny thing when I view the variables, they hold the right totals and yet, they can't be shown on the grid. I suspect this to happen because the record in the reader is declared as this:


{name: 'AdjustmentMonetaryAmount', type: 'string', mapping: 'AdjustmentMonetaryAmount'},


Any help would be greatly appreciated.

Thanks

tBSTAR
27 Jan 2009, 4:08 PM
I found out that removing Ext.util.Format.usMoney fixed my problem because the field has a string type.

return Ext.util.Format.usMoney(sum.toString());

I am still looking for something like the rowExpander plugin but it has to be for the grouped items not per row.
In another words, I I will display additional text below the totals (GroupSummary) as one row and not per cell.

Any help will be appreciated.

Thanks

galdaka
27 Jan 2009, 11:24 PM
Nope - you need to use the MultiGroupSummary extension - as far as I know.

This is because the doGroupEnd method is implemented incrrectly.

I have a version which allows multi level grouping and multigroup summaries - I'll upload the code later today if I get the chance - it's not fully tested etc but it seems to be working for me.

w://

Where is the example?

Greetings,

wayne_o
28 Jan 2009, 2:10 AM
Here you go...

All of the related extensions - as they are in my system.

It'd be great if we could develop this plugin/set of plugins as they provide EXCELLENT - near as damn it - ad hoc reporting!!

[please rename the file to UploadToExt.rar before extracting :) ]

w://

wayne_o
28 Jan 2009, 2:12 AM
I found out that removing Ext.util.Format.usMoney fixed my problem because the field has a string type.

return Ext.util.Format.usMoney(sum.toString());

I am still looking for something like the rowExpander plugin but it has to be for the grouped items not per row.
In another words, I I will display additional text below the totals (GroupSummary) as one row and not per cell.

Any help will be appreciated.

Thanks

You should look at using VS2008 or Aptana for debugging JS - that would have been apparent imediately had you been able to step into the code :)

w://

tBSTAR
28 Jan 2009, 9:06 AM
I hear you bro, I found out the hard way. wayne_o (http://extjs.com/forum/member.php?u=2383) do you happen to know how to add a group expander that takes up the whole row?

shankys_4u
17 Feb 2009, 3:12 AM
Recently, I have started using this MultiGrouping Grid. However I get an error - "Ext.ux.clone is not a function" in FireFox ..Please advise...

wayne_o
17 Feb 2009, 3:39 AM
Please make sure you have the deepclone function included in your scripts :)

http://jaffa.cvs.sourceforge.net/viewvc/jaffa/JaffaRIA/source/html/js/extjs/ux/utils/

w://

wayne_o
17 Feb 2009, 3:40 AM
Sorry for late replying...

What do you mean about having the expander take up the whole row? My version - if I click anywhere on the expander row - it expands/contracts the group.

W://

shankys_4u
17 Feb 2009, 5:51 AM
I have included the DeepClone file...but Still no luck :-( I get error - "Labels is not defined" .... I am using it as per instructions on http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html Please let me know if I am still missing any files to include.

wayne_o
17 Feb 2009, 6:07 AM
I have included the DeepClone file...but Still no luck :-( I get error - "Labels is not defined" .... I am using it as per instructions on http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html Please let me know if I am still missing any files to include.

Sorry - forgot they're suing resources to store their strings in that project so it has a reliance on a variable named 'Labels'.

Try and grab the code in post #134 of this thread -I think all that should work OK.

If not - try and search for the 'Labels' variable and remove the code referencing it.

w://

cgs1999
20 Feb 2009, 1:09 AM
so good!nice work.

oliverseitz
4 Mar 2009, 3:06 AM
Any chance to add to this multigrouping also filters before getting json from server?
filtering by textstring, daterange, etc before doing grouping?

would be nice if you could help me...

thanx in advance.

bye
oliver

nacha
12 Mar 2009, 7:59 PM
Wayne, Can you show me how to use the plugins(the code in post #134), i 've tried the code in my project, but i didnt look the plugins work properly... :(

snowy8781
30 Mar 2009, 10:29 PM
how to add a plugins to multigroupgrid eg, add a summary

denyall
14 Apr 2009, 9:24 AM
Hi,
This is a great extension, but it´s cell editing posible with this extension (multigrouping)?
ty for your atention

denyall
15 Apr 2009, 7:25 AM
Hi,
This is a great extension, but it´s cell editing posible with this extension (multigrouping)?
ty for your atention


its possible :D,

http://extjs.com/forum/showthread.php?p=316772#post316772

Tewr
11 May 2009, 1:26 AM
Hi all,

First of all, Excellent plugin, I find it very useful!

I have found a small bug, it is reproducable on the working example on http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html (I am not sure if this is the "latest" version, but some posts imply that it is?)

How to reproduce:
- Load the page as usual, but make sure that a set of "groupings" are applied.
- Change the column order as in a normal grid, by dragging and dropping the columns just in the grid header. This will, in some cases, render faulty grouping headers. Example: Just after the example has loaded, move the "Serial" column to the way left, and the problem will be obvious. I guess the grouping header does not adapt to the new order in the store...

I will post here again If I find any solution to the problem other than disabling column resorting :P

Regards

Tewr
11 May 2009, 9:05 AM
Turns out this was fixed in the version posted in #134, which apparently is newer :">

If anyone wants to use the old version and avoid this bug, the error lies in doRender in MultiGroupingView, it is fixed by replacing lines containing this.cm.lookup[this.cm.findColumnIndex(t)].header with this.cm.getColumnHeader(this.cm.findColumnIndex(fieldName)).

Regards,
Tor

Maharshi
29 May 2009, 10:30 AM
Hi,

My client has requirements for showing the 2 differnt groups under a grouping grid.Is this possible using MultiGrouping ?please note that i need 2 different group at the same level ,and not 2nd and 3rd level of grouping

For ex

Group A1
|__GroupX1 (first group under Group 1)

|__ GroupY1. (second different group under Group1 but no relation wth Group1.1)

Group A2
|__GroupX2 (first group under Group 2)

|__ GroupY2 (second different group under Group2 but no relation wth Group2.2)


Thanks.

galdaka
29 May 2009, 12:53 PM
Hi,

My client has requirements for showing the 2 differnt groups under a grouping grid.Is this possible using MultiGrouping ?please note that i need 2 different group at the same level ,and not 2nd and 3rd level of grouping

For ex

Group A1
|__GroupX1 (first group under Group 1)

|__ GroupY1. (second different group under Group1 but no relation wth Group1.1)

Group A2
|__GroupX2 (first group under Group 2)

|__ GroupY2 (second different group under Group2 but no relation wth Group2.2)


Thanks.

Use Ext base default grouping grid extension for four pourpose.

Greetings,

Maharshi
31 May 2009, 9:22 PM
Hi,

I am sorry I didnt quite understand your suggestion.Ext Grouping grid as in sample takes only a single fields in 'groupField' while i need 2 levels of grouping.In the sample, the grid is grouped by 'Industry' ,my requirement analogy would be , for ex : show data grouped by 'Industry' (1st level) and then group by 'company' and 'Price' at the same level (2nd level)

+GroupBy Industry (column headers different here)
|__GroupBy Company (column headers will be different here)
|__Child nodes of company group

|__GroupBy Price (column headers different here)
|__child nodes of price

The requirement is showing a grid inside a grid with different data and column headers.
Is there any solution for this using multigrouping grid ?

Thanks,

rene.klatt
2 Jun 2009, 6:16 AM
Hello,

at first, thanks for this great tool. Now to my littleproblem, i want to add my own toolbar to the grid, but it failed.

I tryed to add my tbar in the "var grid = new Ext.ux.MultiGroupingPanel(" like:
tbar: [{
text: 'Eintrag bearbeiten',
tooltip: 'Klicken um einen Eintrag zu bearbeiten',
handler: loadItem,
iconCls: 'edit'
}]

I dont know how to add my own parts to the grid tbar, please help me.

Thank you...

yyogev
16 Jun 2009, 7:04 AM
Hi,

I tried running the Multi-Grouping example shown in http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html, using Ext JS 3.0 RC2, but it showed no records.

Using Firebug I was able to find that the problem is in l.307 in MultiGrouping.js:
text: this.cm.lookup[this.cm.findColumnIndex(t)].header
it looks like cm.findColumnIndex is 0-based, whereas lookup starts from 1.

therefore the following patch can be applied by anyone who wishes to use this code with Ext JS 3.0 RC2 (and probably 3.0 in general):


+++ ./MultiGrouping.js 2009-06-16 18:00:52.434448094 +0300
@@ -299,7 +299,7 @@
if(gfi>0)
ss.addItem(new Ext.Toolbar.Separator());
var b = new Ext.Toolbar.Button({
- text: this.cm.lookup[this.cm.findColumnIndex(t)].header
+ text: this.cm.lookup[this.cm.findColumnIndex(t)+1].header
});
b.fieldName = t;
ss.addItem(b);
@@ -346,7 +346,7 @@

for (var j = 0; j < gfLen; j++) {
fieldName = groupField[j];
- fieldLabel = this.cm.lookup[this.cm.findColumnIndex(fieldName)].header;
+ fieldLabel = this.cm.lookup[this.cm.findColumnIndex(fieldName)+1].header;
v = r.data[fieldName];
if (v) {
if (i == 0) {
HTH
Yaron Yogev

akannu
24 Jun 2009, 11:29 AM
I think that the last version is in: http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

Greetings,

Hello Galdaka
Where can I find the licensing terms for your implementation?

Thanks

galdaka
25 Jun 2009, 12:39 AM
Hello Galdaka
Where can I find the licensing terms for your implementation?

Thanks

Multigroup code is not mine. The author is:

venky0589 (http://extjs.com/forum/member.php?u=28670) http://extjs.com/forum/images/statusicon/user_offline.gif vbmenu_register("postmenu_200586", true);
Ext User

Greetings,

jerrybrown5
25 Jun 2009, 8:23 PM
Hi,

I tried running the Multi-Grouping example shown in http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html, using Ext JS 3.0 RC2, but it showed no records.

Using Firebug I was able to find that the problem is in l.307 in MultiGrouping.js:
text: this.cm.lookup[this.cm.findColumnIndex(t)].header
it looks like cm.findColumnIndex is 0-based, whereas lookup starts from 1.

therefore the following patch can be applied by anyone who wishes to use this code with Ext JS 3.0 RC2 (and probably 3.0 in general):
[/code]HTH
Yaron Yogev

Here is a another hot fix, just manually specify the id property as the ordinal index in each column.

yyogev
26 Jun 2009, 4:15 PM
Here is a another hot fix, just manually specify the id property as the ordinal index in each column.

Hello Jerry,

could you explain what you mean in a more explicit manner, perhaps giving as example how the code line that I gave as example should look.

Thanks,
Yaron Yogev

rickonodera
5 Jul 2009, 9:58 AM
Yaron Yogev

Thanks a lot man, thats a really nice tip!

sawan
6 Jul 2009, 10:52 PM
Hi Venky0589,

I tried to implement multi grouping in my current grid, but could not do it.

It always said h is not defined. I have removed all modifications and below is a clean working copy of the file, can you please suggest modifications.

Thanks in advance.

Once again, it is seriously a very good plugin.

Ext.onReady(function(){
function saveFormData(oGrid_event){
Ext.Ajax.request({
waitMsg: 'Please wait...',
url: 'extjsdataupdate/',
params: {
task: "UPDATES",
id:oGrid_event.record.data.id,
color_name:oGrid_event.record.data.color_name,
brand_name:oGrid_event.record.data.brand_name,
color_code:oGrid_event.record.data.color_code,
hex_value:oGrid_event.record.data.hex_value,
color_family_name:oGrid_event.record.data.color_family_name
},

success: function(response){
var result = eval(response.responseText);
switch(result){
case 1:
ds.commitChanges();
ds.reload();
break;
default:
Ext.MessageBox.alert('Sorry...','Record could not be saved');
break;
}
},
failure: function(response){
var result=response.responseText;
Ext.MessageBox.alert('error','could not connect to the database. retry later');
}
});
}
Ext.menu.RangeMenu.prototype.icons = {
gt: '/images/greater_then.png',
lt: '/images/less_then.png',
eq: '/images/equals.png'
};
Ext.grid.filter.StringFilter.prototype.icon = '/images/find.png';
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var fm = Ext.form;

var filters = new Ext.grid.GridFilters({
filters:[
{type: 'numeric', dataIndex: 'id'},
{type: 'string', dataIndex: 'color_name'},
{type: 'string', dataIndex: 'brand_name'},
{type: 'string', dataIndex: 'color_code'},
{type: 'string', dataIndex: 'hex_value'},
{type: 'string', dataIndex: 'color_family_name'}
]});

var cm = new Ext.grid.ColumnModel([
new Ext.grid.RowNumberer(),
{dataIndex: 'id', header: 'Color ID', id: 'id'},
{dataIndex: 'color_name', header: 'Color Name', editor: new fm.TextField({allowBlank: false}) },
{dataIndex: 'brand_name', header: 'Brand Name'},
{dataIndex: 'color_code', header: 'Color Code', editor: new fm.TextField({allowBlank: false}) },
{dataIndex: 'hex_value', header: 'Hex Value', editor: new fm.TextField({allowBlank: false}) },
{dataIndex: 'color_family_name', header: 'Color Family Name'}
,
{dataIndex: 'id', header: 'View', renderer: idViewRenderer},
{dataIndex: 'id', header: 'Edit', renderer: idEditRenderer},
{dataIndex: 'id', header: 'Remove', renderer: idRemoveRenderer}
]);

cm.defaultSortable = true;
function idViewRenderer(val){
if(val != null){
return "<a href='/mcolor/view/id/"+ val +"'>View</a>";
}
return val;
}
function idEditRenderer(val){
if(val != null){
return "<a href='/mcolor/edit/id/"+ val +"'>Edit</a>";
}
return val;
}
function idRemoveRenderer(val){
if(val != null){
return "<a href='/mcolor/remove/id/"+ val +"'>Remove</a>";
}
return val;
}

var reader = new Ext.data.JsonReader({
totalProperty: 'total',
root: 'data',
fields: [
{name:'id'},
{name:'color_name'},
{name:'brand_name'},
{name:'color_code'},
{name:'hex_value'},
{name:'color_family_name'}
]
});

var ds = new Ext.data.GroupingStore({
proxy: new Ext.data.HttpProxy({url:'/mcolor/extjsdata/id/0'}),
reader: reader,
sortInfo:{field: 'id', direction: "ASC"},
groupField:'brand_name'
});

var grid = new Ext.grid.EditorGridPanel({
store: ds,
view: new Ext.grid.GroupingView({
forceFit:true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
}),
cm: cm,
plugins: [filters, Ext.ux.plugins.Print],
tools:[{id:'mybutton',handler: function(){window.open('/mcolor/add','_parent')}}],
loadMask: true,
renderTo: 'grid-example',
width: '100%',
height:600,
title:'List of Color',
frame: true,
stripeRows: true,
trackMouseOver: true,
autoSizeColumns: true,
clicksToEdit:1,

tbar: new Ext.PagingToolbar({
pageSize: 25,
store: ds,
displayInfo: true,
plugins: [filters, Ext.ux.plugins.Print]
}),
});
ds.load({params:{start: 0, limit: 25}})
grid.render();
grid.on('afteredit', saveFormData);
});

Nam
8 Jul 2009, 10:05 AM
If I add a row to the grid, instead of it being grouped under the correct group, A new duplicate group is created.


I'm grouping by a "Type" field... which when grouped have the following groups...

Firewall, LoadBalancer, Router, Server, and Switch

But, when I add a new row, instead of being grouped under for instance... "Firewall"... what happens is a new group is created (even if it already exists), and the item is put under there...

So... basically it does this...

+ Firewall
Item....
Item....
+ LoadBalancer
Item....
+ Router
Item....
+ Server
Item....
+ Switch
Item....
+ Firewall
New Item....


If I remove 'Type' from grouping, and then re-add it, the new item is in the correct place, but is there anything that needs to be called in order to get the multigroupingpanel to do this properly on it's own?

janasri
10 Jul 2009, 2:46 PM
This looks like a great extension. Was there an official release of this extension? I need to implement multi grouoing (with 3 or 4 levels). Where can I get the latest code for this?

Regards

dbojdo
11 Jul 2009, 1:21 AM
hi, i tested multigroup extension (i don't know if it's latest one) i found on http://www.jadacosta.es/extjs/examples/multigroup3/MultiGroup.html

there is a problem with MultiGroupingStore when it works in remote mode sort or/and group
in sort case there is no info about sort field and direction in request
in group case there is information about latest group column, but there should be an array of all group fields...

but it's really very useful extension, good work

regards

Karmaresh
14 Jul 2009, 1:51 AM
Is there an example of multiple grouping in which the data is local and no server side communication is done ??

yyogev
14 Jul 2009, 10:59 AM
Is there an example of multiple grouping in which the data is local and no server side communication is done ??


http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

look in ux/Multi.js - it uses orders.json, which is a local file.

HTH,
Yaron Yogev

yyogev
14 Jul 2009, 11:06 AM
This looks like a great extension. Was there an official release of this extension? I need to implement multi grouoing (with 3 or 4 levels). Where can I get the latest code for this?

Regards

Hi,

looking on the Ext site I see this extension is not in the extensions list:
http://extjs.com/learn/Ext_Extensions

I am not sure why it is so. I really wish there was a central repository for all user extensions, so that one can easily fetch the latest code, even if it's not supported by Ext company. Looking through all the threads and various places on the web is very confusing.

Yaron Yogev

yyogev
14 Jul 2009, 11:31 AM
Hi,

There were patches available here for the Multi-Grouping user extension that enabled one to work with editable grid fields, and to use the Group Summary plugin. However, these were two separate patches, and I needed to have both fixes implemented for my purposes.

I therefore merged the code of these patches, and also:
Fixed group summary to use ParseFloat on numeric types
Fixed group summary to update summaries on all affected groups when a field is updated in a row.
Added summary_colors list and show_summary_colors boolean (default: true) to display summary rows in different colors
Added show_group_title (default: true) - if true, adds a 'title=' HTML attribute to the summary row, displaying a pop-up message "summary for this X' where X is the group's 'text' value, i.e. the header for the column by which this grouping is done, e.g. "Industry".
Added back some of the remarks taken out by SIDGEY in his patch for using editable fields
De-minified some of SIDGEY's code. It's too hard to maintain & debug that way. If I want a file minified, I'll create a minified version to serve on my production server.
I changed some of the code to match my code writing style. Sorry, but then again, there's no one standard here AFAIK, and it's still better than what I've seen in the minified code mentioned above.Attached are MultiGrouping.js and GroupSummary.js.
If anyone wants to view the changes, I can supply the difference as a patch file.

I know there are more unsolved issues with this code, e.g. no redraw of summary rows after resize.
If you have any more fixes to add, please post them on this thread.

HTH,
Yaron Yogev

Karmaresh
30 Jul 2009, 6:18 AM
http://www.jadacosta.es/extjs/examples/multigroup/MultiGroup.html

look in ux/Multi.js - it uses orders.json, which is a local file.

HTH,
Yaron Yogev

Dont need a local file .. need local data like the one provided in the first zip attached in the thread .. i.e the first one .. in that source code everything is working fine in FF but its giving object expected error in IE .. I still can't figure out why that error ??

Karmaresh
30 Jul 2009, 6:57 AM
Two things:

1) Not works in IE6. But works fine in FF2!!.

2) Is posible add extra CSS for remove / customize extra lines in categorized rows?


I think this way is the best / easy solution for trasform a grid in a treegrid!!!

I upload the fixed version of "MultiGroup.html" for extract in "ext-2.1\examples\sourceMg" and run!!

Thanks in advance,


What's the reason it was not working in IE ?? got any hint on that ??

giovanni
30 Jul 2009, 9:36 AM
Great extension, however I get an object expected error (IE7) if I set displayEmptyFields: false on group view and null one of the part values in the json. We are using Ext 3.0 btw.

Anyone else having this problem?

Thanks

Karmaresh
30 Jul 2009, 12:04 PM
Great extension, however I get an object expected error (IE7) if I set displayEmptyFields: false on group view and null one of the part values in the json. We are using Ext 3.0 btw.

Anyone else having this problem?

Thanks


yes there are extra commas in the multigrouping.js files. Just remove them and it would work fine ...

The code below is somewhere around line 373 ...


for (jjj = 0; jjj < groupField.length; jjj++) {
if (g.substring(0, g.indexOf(':')) == groupField[jjj])
break;
}
if (k == grpDisplayValues.length - 1) {
curGroup = {
group: g,
gvalue: gvalue[k],
text: g,
groupId: gid,
startRow: rowIndex,
rs: [r],
cls: gcls,
style: gstyle+'padding-left:'+(jjj*12)+'px;', (remove this comma)
}
}else {
curGroup = {
group: g,
gvalue: gvalue[k],
text: g,
groupId: gid,
startRow: rowIndex,
rs: [],
cls: gcls,
style: gstyle+'padding-left:'+(jjj*12)+'px;', (remove this comma)
};
}

just remove the unwanted commas and it would run in IE .. at least its running in IE8

giovanni
30 Jul 2009, 12:51 PM
Hi Karmaresh,

Thanks for the reply. I'm using the version posted by yyogev and can't locate the extra commas there. I've zipped it and attached it. Thanks for the help

Gio

Karmaresh
30 Jul 2009, 9:47 PM
Hi Karmaresh,

Thanks for the reply. I'm using the version posted by yyogev and can't locate the extra commas there. I've zipped it and attached it. Thanks for the help

Gio


I was refering to the zip attached in the first post in the thread.

ut_paule
5 Aug 2009, 10:24 AM
Hi Karmaresh,

Thanks for the reply. I'm using the version posted by yyogev and can't locate the extra commas there. I've zipped it and attached it. Thanks for the help

Gio

This widget is being actively maintained as part of a the JaffaRIA project, so if you're just interested in getting the latest copy of the code from this source as opposed to the zip files posed on this forum it can be found at the following location which is part of a SVN repository on sourceforge. http://jaffa.svn.sourceforge.net/viewvc/jaffa/trunk/JaffaRIA/source/html/js/extjs/ux/grid/
(http://jaffa.svn.sourceforge.net/viewvc/jaffa/trunk/JaffaRIA/source/html/js/extjs/ux/grid/)
You can also use this link to see the complete change log of modifications we have made in SVN. We are actively using this widget with Ext 2.2 (we have not yet migrated/tested it against Ext 3.0, but i expect that will happen before the end of the year)
We generally test it using IE6/7 and FF2/3 (and i expect we'll soon need to be doing IE8 and FF3.5 probably as we go to Ext 3.0)

If anyone wants me to apply a patch to the SVN version send me a mail (ut_paule (at) users.sf.net) as i don't always catch the posts to this thread.

We are currently looking into the use of the GroupingSummary plugin, as many people have noted it is broken, so if anyone already has a patch for this already send it to me and we'll try and incorporate it.

Thanks

PaulE

timmy
5 Aug 2009, 3:35 PM
Your link is broken above to your svn repo.

ut_paule
5 Aug 2009, 3:50 PM
Your link is broken above to your svn repo.

Must be an issue with SourceForge's ViewVC, as it was working when i posted it....

If you want the code this link is still working... http://jaffa.svn.sourceforge.net/svnroot/jaffa/trunk/JaffaRIA/source/html/js/extjs/ux/grid/

You just can't see the revision history (unless you view it via TortoiseSVN!)

Azadi
11 Aug 2009, 11:46 AM
Hi venky0589,

I tried downloading your solution for MultiGroup with json and I'm getting the following error: "Cannot open file: it does not appear to be a valid archive." Could you please re-post your solution?


Thanks

galdaka
11 Aug 2009, 12:36 PM
Hi,

This extension works in Ext 3.0.0?

Where is the example code?

Theses links not works: http://jaffa.svn.sourceforge.net/svnroot/jaffa/trunk/JaffaRIA/source/html/tests/extjs/multigroup/MultiGroup.html

Greetings,

blackghost
21 Aug 2009, 10:41 AM
Hey man, I am new guy and I am very appreciate everyone to build interested plug-in

blackghost
22 Aug 2009, 5:38 AM
hey guy, if I build one grid which group by 2 fields - multiple grouping and of couse I also have 2 summary field, how can I know to determine the position where is current summary field ? because I need change label of each kind of summary.

Ext.ux.grid.GroupSummary.Calculations['total'] = function(v, record, field){
var sum = "Total ";
return sum;
};

Ext.apply(this, {
iconCls: 'icon-grid',
store: store,
columns:[
{header: 'Group1',hidden: true, dataIndex: 'Group1'},
{header: 'Group2',hidden: true, dataIndex: 'Group2'},
{header:'Date',sortable: true, dataIndex: 'Date',
align: 'right',
summaryType: 'total',
summaryRenderer: function(v, params, data)
{
return v;
}
},
{header:'Count',sortable: false, dataIndex: 'Count'}
],
plugins: new Ext.ux.grid.GroupSummary(),
view: groupView
});

Any ideas, I'm very appreciated

yyogev
22 Aug 2009, 10:34 PM
hey guy, if I build one grid which group by 2 fields - multiple grouping and of couse I also have 2 summary field, how can I know to determine the position where is current summary field ? because I need change label of each kind of summary.


Hi blackghost,

AFAIK, the group summary plugin only adds summary rows, so I'm not sure what you mean when you talk about.
What you get is for every column where you add summary you will see a summaries row for every group, with summary value below each summarized column.

yyogev
22 Aug 2009, 10:46 PM
This extension works in Ext 3.0.0?


Hi galdaka,

I use it with ExtJS 3.0 RC2. I need to move to 3.0.0., but it didn't work right away when I tried it, so I postponed that for a while.
Attached is my latest version of MultiGrouping.js and GroupSummary.js.

HTH

blackghost
22 Aug 2009, 11:09 PM
hi yyogev,
I'm very appreciate your answer my question, thanks.
Normally,

Root
|-----Group X
|------------Group Y
|------------Item1.0---------Item1.1-----------------------Item1.2
|------------Total-----------Sum(Item1.1)-----------------Sum(Item1.2)
|------------Group Y
|------------Item2.0---------Item2.1----------------------Item2.2
|------------Total-----------Sum(Item2.1)-----------------Sum(Item2.2)
|------------Total-----------Sum(Item1.1 & Item 2.1)------Sum(Item1.1 & Item 2.1)


And source code :

Ext.ux.grid.GroupSummary.Calculations['total'] = function(v, record, field){
var sum = "Total "; --> How can I know Where is current grouping field.( Group X or Group Y ??? --> return suitable value)
return sum;
};

Ext.ux.grid.GroupSummary.Calculations['Count1'] = function(v, record, field){
var sum = v + record.get('Count1');
return sum;
};

Ext.ux.grid.GroupSummary.Calculations['Count2'] = function(v, record, field){
var sum = v + record.get('Count2');
return sum;
};


Ext.apply(this, {
iconCls: 'icon-grid',
store: store,
columns:[
{header: 'GroupX',hidden: true, dataIndex: 'GroupX'},
{header: 'GroupY',hidden: true, dataIndex: 'GroupY'},
{header:'Date',sortable: true, dataIndex: 'Date',
align: 'right',
summaryType: 'total',
summaryRenderer: function(v, params, data)
{
return v;
}
},
{header:'Item1',sortable: false, dataIndex: 'Count1',
summaryType: 'Count1',
summaryRenderer: function(v, params, data)
{
return v;
}
} ,
{header:'Item2',sortable: false, dataIndex: 'Count2',
summaryType: 'Count2',
summaryRenderer: function(v, params, data)
{
return v;
}
} ,
],
plugins: new Ext.ux.grid.GroupSummary(),
view: groupView
});

Give me some advice, some way.Thank so much.

yyogev
22 Aug 2009, 11:19 PM
After talking with blackghost over off the forum, here's the summary:
blackghost wanted to display on summary row which group it summarized.
my answer was this:

If you look at the changes I made in the plug-in, you'll see I added config item show_group_title, which allows displaying a tooltip title when the user has the mouse pointer over the summary line.

It is possible to change the template of the row to include the description as you wish - this should be done in the same place where I've put the code for displaying the tooltip.
However, the problem with this is that it pushes the other columns to the right (assuming LTR page), which is why I chose to put tooltip instead. Also consider the fact that it creates more "noise" for the user. I prefer less permanent text. I even allow the user to choose to not show summaries at all.

wp.joju
8 Sep 2009, 1:45 AM
i just got 2 things to confirm:
1. when i group by a column with an "id", it throws an error. is this a confirmed bug?
2. is groupFieldTemplates attribute of the store working? because the template that the grid is using is still the value set in the grid view's groupTextTpl attribute. if this is working how can i make the grid use the values set in the "groupFieldTemplates"

dileep singhal
14 Sep 2009, 2:27 AM
Hi Yogev sir,

I am using your multigroupin js with ext 3.0 version i used your patch for comaptability of 3.0 ext......but i facing problem related to grouping tool bar that it is not sowing me groupin list on top of the table please help me

Thanks & regard
Dileep Singhal
Yaron Yogev[/QUOTE]

yyogev
14 Sep 2009, 2:38 AM
Hi Yogev sir,

I am using your multigroupin js with ext 3.0 version i used your patch for comaptability of 3.0 ext......but i facing problem related to grouping tool bar that it is not sowing me groupin list on top of the table please help me

Thanks & regard
Dileep Singhal

:(
Sorry - I failed to mention that this problem exists for me as well. I only needed to have two types of grouping for my users, so I solved this by wrapping the grid in a panel and using that panel's top toolbar for all types of user selections, including grouping type.

This can probably be solved with some effort using Firebug. Unfortunately it is placed low in my To-Do list.

daltonjorge
15 Sep 2009, 9:13 AM
Hi! I've made some modifications in the MultiGrouping.js (doRender event) and the toolbar is visible again:


,doRender: function(cs, rs, ds, startRow, colCount, stripe){
var ss = this.grid.getTopToolbar();
if (rs.length < 1) {return '';}
var groupField = this.getGroupField();
var gfLen = 0;
if(groupField){
gfLen = groupField.length;
}
for (var i = 0; i < cs.length; i++)
cs[i].style = this.getColumnStyle(i, false);

// Remove all entries alreay in the toolbar
ss.removeAll();

if (gfLen==0)
ss.addItem(new Ext.Toolbar.TextItem("Drop Columns Here To Group"));
else {
// Add back all entries to toolbar from GroupField[]
ss.addItem(new Ext.Toolbar.TextItem("Grouped By:"));
for (var gfi = 0; gfi < gfLen; gfi++) {
var t = groupField[gfi];
if (gfi>=0) {
ss.addItem(new Ext.Toolbar.Separator());
var b = new Ext.Toolbar.Button({
fieldName: t,
text: this.get_column_by_id(t).header
});
ss.addButton(b);
}
}
}
ss.doLayout(); // <- is required after adding a new component
...

But I'm still having problems with the grouping of several columns :(.
--
Dalton Jorge

daltonjorge
15 Sep 2009, 11:08 AM
Hi, I changed the lines below (MultiGrouping.js:57) and now the grouping is fine!:D

Before:


if (this.groupField)
{
for (var z = 0; z < this.groupField.length; z++)
{
if (field == this.groupField[z])
return;
this.groupField.push(field);
}
}
After:


if (this.groupField)
{
if (this.groupField.indexOf(field) > 0) {
return;
}
this.groupField.push(field);
}

dileep singhal
15 Sep 2009, 8:33 PM
Dear DELTONGORGE sir,

According to you mention/suggest the following changes in multigrouping js should be complete so we can resolve the issue (grouping bar not showing properly when we drag & drop a group filed) . so i did that sir in my multigrouping js but it showing me javascript error. I am sending you my sample files for your observation. Please Take appropriate attention toward it resolve the problem.

Thanking you

daltonjorge
16 Sep 2009, 4:40 AM
Hi dileep singhal, I didn't receive your files yet.
I didn't try to group by using the "drag & drop". I just used the grouping menu.

dileep singhal
16 Sep 2009, 8:37 PM
Dear deltojorge,

SIr sorry i am using your patch in multigrouping js but it is not showing any data table for me so it hav error. SIr my problem (without using your patch) is first time data and group tool bar filling data very well but when i try to change the group the group tool bar is not showing....:"> If u did this job through the group menu then please provide us. so please check this and possible solution find for our community...

thanks

dileep

daltonjorge
16 Sep 2009, 9:25 PM
Dear dileep,

I tested your sample with my "MultiGrouping.js" version and everything is ok. Please, replace your "MultiGrouping.js" with this attachment (my version) and try again.
Regards,
Dalton Jorge

PS: I tested here only with Firefox and Opera browsers. I don't use ms-windows.

dileep singhal
16 Sep 2009, 9:49 PM
Dear dileep,

I tested your sample with my "MultiGrouping.js" version and everything is ok. Please, replace your "MultiGrouping.js" with this attachment (my version) and try again.
Regards,
Dalton Jorge

PS: I tested here only with Firefox and Opera browsers. I don't use ms-windows.


Sir please check your js file formatting which u put on forum whythway i found the right solution for the problem i wnat to share with u

daltonjorge
16 Sep 2009, 9:58 PM
Sorry, I didn't understand your message. I sent you again without compression.

dileep singhal
16 Sep 2009, 10:17 PM
Sorry, I didn't understand your message. I sent you again without compression.
thanks sir both your solution working fine and also mine thanks a lot .....can u give me grouping with summury example ?? if possible please send ...tnx

dileep

yyogev
16 Sep 2009, 10:39 PM
Hello dileep & dalton,

Since I am listening on this thread, I get all of this messages that you send via the thread. It would be nicer if you could use private messages for such correspondence.

Thanks,

daltonjorge
16 Sep 2009, 10:51 PM
Sorry yyogev, it wasn't my intention to perturb this thread.:s
--
Dalton Jorge
Software Engineer
Portal Tecnologia

dileep singhal
17 Sep 2009, 12:34 AM
Sorry yyogev,

I am Really sorry but it is did for all users which they could take more advantage..
>:)
Dileep

dileep singhal
20 Sep 2009, 11:03 PM
hi Wayne_o,

Actually i done multigrouping on table but when iam using summury with multigrouping it is not working properly can you send your sample multigrouping with summury....thats why i identify where iam doing mistake ......plz

thanks

sim
30 Sep 2009, 9:04 AM
Anybody able to get REMOTE SORTING (column header click) or REMOTE GROUPING work?

Here, its firing an ajax call to proxy's url, but no information for SORT and DIR
POST parameters when remoteSort: true.

Any experience on this issue?

/Sim

sim
30 Sep 2009, 9:25 AM
oh, might have to use this

Ext.ux.grid.MultiGroupingPagingStore

checking, checking

emily
1 Oct 2009, 8:00 AM
Hi,

I ran into a problem trying to use this user extension with the RowActions one written by Saki.

After quite a bit of debugging and recoding the doRender function, I managed to get them working together.

What didn't work in MultiGrouping was the the r._groupId wasn't being set for every row, only rows following the grouping row. This caused RowActions to barf when trying to call the queryBy function. It seemed sensible to me that the r._groupId should really be set for every row so no matter which row you want to select for whatever reason you know which groups it belongs to in the current rendering (like the GroupingView.doRender function does).

Also the groupId for those groups were only taking consideration the child group, if there were any parent groups, this info wasn't available, so I changed that so the groupId was of the form:


blah + '-gp-' + parent_field + '-' + parent_value + '-' + ... + '-' + child_field + '-' + child_value

This means that if you have any groupactions, you know exactly what grouping has been used to filter the data, and also which data fall under this grouping. This enables you to create useful callback functions.

I have attached my version of the code. I did have to rename a lot of variables to get my head around it (so I could figure out how to fix it), and I also removed some seemingly redundant variables (that were being set / declared that weren't ever read).

If any of my renamings seem silly, feel free to change them and post back. I am new to ExtJS so there may be naming conventions for things that I am unaware of (but using B as a variable name for a renderer doesn't seem sensible to me!).

Both UXs now work for me using ExtJS 3.0.

Em

rpnoble
23 Oct 2009, 12:50 PM
Group;

I'm using this plug-in in a touch screen application. When the font size is increased to allow for a finger touch, the left hand padding is not great enough to allow for a clean look. I added the following code to make it adjustable:

I'm using an older version as I have not yet moved to EXTJS 3.0

in the MultiGrouping.js -> Ext.ux.MultiGroupingView section, I added:

offsetLeft: 12,

Then I replace all occurences of

padding-left:" + (gfLen*12) + "px}"

with

{padding-left:" + (gfLen * this.offsetLeft) + "px}"

Now I can adjust the left side padding when I define my grid using the following:



view: new Ext.ux.MultiGroupingView({
hideGroupedColumn:true,
offsetLeft: 60,
emptyGroupText: 'All Group Fields Empty',
displayEmptyFields: true,
forceFit:true,
startCollapsed:true,
showGroupName:false,
groupTextTpl: '{gvalue} ({[values.rs.length]} {[values.rs.length == 1 ? "Document" : "Documents"]})',
displayFieldSeperator: ', ' //you can control how the display fields are seperated
}),


I hope this helps....

isit.gd
28 Oct 2009, 3:44 AM
emily (http://www.extjs.com/forum/member.php?u=23119) - the improvements you made to the grid are brilliant - i'm just adding back in the group templates stuff and will post it back when done - thanks for adding to the ux :)

isit.gd
28 Oct 2009, 3:58 AM
et voila :)

emily
28 Oct 2009, 4:15 AM
emily (http://www.extjs.com/forum/member.php?u=23119) - the improvements you made to the grid are brilliant - i'm just adding back in the group templates stuff and will post it back when done - thanks for adding to the ux :)

Thanks :)

I did find a small bug that I had missed in the one I uploaded - I had forgotten to remove one of the redundant bits of code (line 321, but you have commented it out in your version :) ).

Unfortunately the data I am trying to use this with is far too large so I have had to write an alternative (using ColumnTree and some drag and drop stuff). What I really wanted is a MultiGroupingLiveGrid (with rowactions), but I think that is like asking for the moon on a stick! I think it would be possible, but would take forever to code.

isit.gd
28 Oct 2009, 4:46 AM
Thanks :)

I did find a small bug that I had missed in the one I uploaded - I had forgotten to remove one of the redundant bits of code (line 321, but you have commented it out in your version :) ).

Unfortunately the data I am trying to use this with is far too large so I have had to write an alternative (using ColumnTree and some drag and drop stuff). What I really wanted is a MultiGroupingLiveGrid (with rowactions), but I think that is like asking for the moon on a stick! I think it would be possible, but would take forever to code.

have you tried using the paging grouping grid?

i've not looked at it yet

emily
28 Oct 2009, 7:59 AM
have you tried using the paging grouping grid?

i've not looked at it yet

Not really, but paging is not really suitable for my purposes. My data needs to be easily browsable / sortable, and paging makes this annoying.

wp.joju
4 Nov 2009, 9:19 PM
anybody using the grid row reodering using drag and drop with this one? it doesn't seem to be working

wp.joju
4 Nov 2009, 9:43 PM
is there anyway to adjust the grid width because the last column is getting push under the vertical scrollbar since the column gets indented because of the grouping....


hi there, how can i expand all groups including all the sub groups?

dmichael
6 Nov 2009, 12:20 PM
I am using the MultiGroupingView to categorize documents of all types via a UCM(universal content manager) and I have a need that after I do my search, I want to expand the resulting groups so that my users do not have to click further to reach their documents. I have not found anything that seems to do this and I am hard pressed to believe I am the only person who has ever tried to use this extension in this way. The regular GroupingView's(which also works on the MultiGroupingView) collapseAllGroups() and expandAllGroups() only work to the first level of depth. Does anyone have any experience with this problem and if so, how did you fix it.

Thanks!

emily
6 Nov 2009, 12:51 PM
Does anyone have any experience with this problem and if so, how did you fix it.

Not that functionality in particular, but if the functionality isn't already there, I am sure it wouldn't be very hard to add it. Just look to see how it is done in GroupingView, then override those functions, and loop through all the groups. Maybe look to see what CSS classes the grouping rows have, and get at them that way? If they don't have a common class, you can always add one in.

wp.joju
18 Nov 2009, 2:10 AM
anyone able to add tooltip to group header (different tooltip text for each header and grouping levels)

dileep singhal
20 Nov 2009, 3:38 AM
WP.Joju,


Hey it is very simple to add tooltip in grouping buttons.In multigrouping js file Line no. 304 add tooltip as
var b = new Ext.Toolbar.Button({text: this.cm.lookup[this.cm.findColumnIndex(t)].header,tooltip:'dileep singhal'});


Enjoy

vladcd
25 Nov 2009, 1:51 AM
I don't know if this is still interesting for people, but I found a way to solve that annoying lines expanding bug(tested on FF 3.5, IE7 and IE8). Hopefully, noone commited this modifications beforehand (didn't have the time to read the previous posts, unfortunatelly)

All the modifications are made in MultiGroupingView.js:
- added paddingStyle variable to template


<div class="x-grid-group-title" style="{paddingStyle}">
- replaced padding of the div that contains the title with padding for the title div, and also with a background position (for the + image)


curGroup = {
group : rndr ? rndr(grp.value) : grp.value,
groupName : grp.dataIndex,
gvalue : grp.value,
text : grp.header,
groupId : gid,
startRow : rowIndex,
rs : [ r ],
cls : gcls,
style : gstyle,
paddingStyle : 'padding-left:'
+ (15 + addedPadding)
+ 'px;background-position:'
+ addedPadding + 'px;'
};

isit.gd
25 Nov 2009, 1:53 AM
what do you mean: annoying lines expanding bug?

:)

w://

vladcd
25 Nov 2009, 2:05 AM
So I took the sources from http://jaffa.sourceforge.net/JaffaRIATests/tests/extjs/multigroup/MultiGroup.html and I saw that there are 2 known issues of this component. One of them concerns 'Width of grouping lines is not correct' (check picture 1).

With my modifications, this doesn't happen anymore(check picture 2).

vladcd
25 Nov 2009, 2:07 AM
Forgot a line of code :D



var addedPadding = grp.idx * 12;
curGroup = {
group : rndr ? rndr(grp.value) : grp.value,
groupName : grp.dataIndex,
gvalue : grp.value,
text : grp.header,
groupId : gid,
startRow : rowIndex,
rs : [ r ],
cls : gcls,
style : gstyle,
paddingStyle : 'padding-left:'
+ (15 + addedPadding)
+ 'px;background-position:'
+ addedPadding + 'px;'
};

extjsnewb
3 Dec 2009, 9:25 PM
Does this extension support ExtJs 3.0?

I am new to ExtJs, so maybe I am just retarded. However, when testing various versions (the sourceforge one from svn, emilies, and one other one) they all almost worked, but some major bugs were there.

For example, the tab bar was not displaying. The latest one from sourceforge svn said missing Ext.ux.clone(), the latest one from sourceforge "options" menu in the tab bar (not the demo on the site... That is not running the latest) is not fully implemented.

So, is this a 2.0 extension only? Is there one for 3.0?

emily
4 Dec 2009, 12:15 AM
Does this extension support ExtJs 3.0?

I am new to ExtJs, so maybe I am just retarded. However, when testing various versions (the sourceforge one from svn, emilies, and one other one) they all almost worked, but some major bugs were there.

For example, the tab bar was not displaying. The latest one from sourceforge svn said missing Ext.ux.clone(), the latest one from sourceforge "options" menu in the tab bar (not the demo on the site... That is not running the latest) is not fully implemented.

So, is this a 2.0 extension only? Is there one for 3.0?

I use extjs 3.0, so I don't think that is a problem. It may be a problem with how you are using it. Do you want to post some code?

Em

extjsnewb
5 Dec 2009, 6:45 PM
I use extjs 3.0, so I don't think that is a problem. It may be a problem with how you are using it. Do you want to post some code?

Em

Hey Emily,

I am using your code because I need the row actions. I have everything working perfect in 2.3.0 with one exception.... Instead of listing groups like this: "Column name: Row Value" it is listing groups like this: "Column name: dataIndex"

I will post some code. Give me one second. Btw, I changed the name of your classes to match the original, but it is your code.

extjsnewb
5 Dec 2009, 6:53 PM
** deleted unneeded stuff **

Imagine that, I spend a few hours on it and the solution was simple. All I needed to do was change {group} to {gvalue} in the templates.

xiaofei
5 Dec 2009, 9:27 PM
Thanks

mrbeig9
15 Dec 2009, 8:12 AM
Hi all,

Thanks for the wonderful plugin. I m new to Extjs and i m still in learning stage. I need some help in removing a Headers whenever there is no value in the group field. The rows should be displayed in the parent grid.
This is my htm file


<script type="text/javascript">
Ext.onReady(function() {
Ext.QuickTips.init();
var xg = Ext.grid;
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var WorkOrderRecord = Ext.data.Record.create([
{ name: 'Parameter' },
{ name: 'Value' },
{ name: 'group1' },
{ name: 'group2' }
// { name: 'group3' }
]);

var reader = new Ext.data.ArrayReader({}, [
{ name: 'Parameter' },
{ name: 'Value' },
{ name: 'group1' },
{ name: 'group2' }
// { name: 'group3' }
]);
var groupStore = new Ext.ux.grid.MultiGroupingStore({
data: xg.dummyData1
, reader: reader
, sortInfo: { field: 'Parameter', direction: 'ASC' }
, groupField: ['group1','group2']
});

var groupView = new Ext.ux.grid.MultiGroupingView({
hideGroupedColumn: true
, emptyGroupText: ''
, displayEmptyFields: true //you can choose to show the group fields, even when they have no values
, groupTextTpl: '{gvalue}' //({[values.rs.length]} {[values.rs.length > 1 ? "Events" : "Event"]})'
// : {group} ' +
// '({values.rs.length} ' +
// 'Record{[values.rs.length>1?"s":""]}) ' +
// '/ Total Material Cost={[fm.usMoney(values.rs.sum("materialCosts"))]}'
// Templates can be set up per grouping field if required
// , groupFieldTemplates: {
// 'serial': 'Special Grouping For Serial Number {gvalue}'
// , 'ecd': '{text}: {[todayString==values.group?"Today":yesterdayString==values.group?"Yesterday":values.group]}'
// }
});
var grid = new Ext.ux.grid.MultiGroupingGrid({
store: groupStore
, columns: [
{ id: 'Parameter', header: 'Parameter', width: 100, sortable: true, dataIndex: 'Parameter' }
, { header: 'Value', width: 100, sortable: true, dataIndex: 'Value' }
, { header: 'group1', width: 20, sortable: true, hidden: true, dataIndex: 'group1' }
, { header: 'group2', width: 20, sortable: true, hidden: true, dataIndex: 'group2' }
// , { header: 'group3', width: 20, sortable: true, hidden: true, dataIndex: 'group3' }
]
, stateful: true
, view: groupView
, width: 900
, height: 400
, collapsible: true
, animCollapse: true
, title: 'Grouping Example'
, iconCls: 'icon-grid'
, renderTo: document.body
, selModel: new Ext.grid.RowSelectionModel({
listeners: {
scope: this
, 'rowselect': function(rsm, rowIndex, r) {
console.debug("rowselect : ", rsm, rowIndex, r);
Ext.Msg.show({
title: 'Show Details',
msg: 'You have selected Work Order ' + r.data.workOrderNo,
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.INFO
});
}
}
})
});
});
Ext.grid.dummyData1 = [
['Test1', 'JS1', 'Header1', 'Header2'],
['Test2', 'JS2', 'Header1', 'Header2'],
['Test3', 'JS3', 'Header1', 'Header2'],
['Test4', 'JS4', 'Header1', 'Header2'],
['Test5', 'JS5', 'Header1', 'Header2'],
['Test6', 'JS6', 'Header1', 'Header2'],
['Test1', 'JS1', 'Header3']
];

</script>

This is the Plugin.. note that some code is commented as i dont need that functionality


/**
* @author chander, adapted by SIDGEY
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//------------------------------------- MULTI GROUPING STORE ----------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////////////////////////////////
Ext.ns('Ext.ux.grid');
Ext.ux.grid.MultiGroupingStore = Ext.extend(Ext.data.GroupingStore, {
constructor: function(config) { Ext.ux.grid.MultiGroupingStore.superclass.constructor.apply(this, arguments); },
sortInfo: [],
sort: function(field, dir) {
var f = [];
if (Ext.isArray(field)) { for (var i = 0, len = field.length; i < len; ++i) { f.push(this.fields.get(field[i])); } }
else { f.push(this.fields.get(field)); }
if (f.length < 1) { return false; }
if (!dir) {
if (this.sortInfo && this.sortInfo.length > 0 && this.sortInfo[0].field == f[0].name) {
// toggle sort direction
dir = (this.sortToggle[f[0].name] || "ASC").toggle("ASC", "DESC");
}
else
dir = f[0].sortDir;
}
var st = (this.sortToggle) ? this.sortToggle[f[0].name] : null;
var si = (this.sortInfo) ? this.sortInfo : null;
this.sortToggle[f[0].name] = dir;
this.sortInfo = [];
for (i = 0, len = f.length; i < len; ++i) {
this.sortInfo.push({ field: f[i].name, direction: dir });
}
if (!this.remoteSort) {
this.applySort();
this.fireEvent("datachanged", this);
}
else {
if (!this.load(this.lastOptions)) {
if (st) { this.sortToggle[f[0].name] = st; }
if (si) { this.sortInfo = si; }
}
}
return true;
},
setDefaultSort: function(field, dir) {
dir = dir ? dir.toUpperCase() : "ASC";
this.sortInfo = [];
if (!Ext.isArray(field)) { this.sortInfo.push({ field: field, direction: dir }); }
else {
for (var i = 0, len = field.length; i < len; ++i) {
this.sortInfo.push({ field: field[i].field, direction: dir });
this.sortToggle[field[i]] = dir;
}
}
},
groupBy: function(field, forceRegroup) {
if (!forceRegroup && this.groupField == field)
return; // already grouped by this field
if (this.groupField) {
if (this.groupField.indexOf(field) > 0) {
return;
}
this.groupField.push(field);
}
else { this.groupField = [field]; }
if (this.remoteGroup) {
if (!this.baseParams) { this.baseParams = {}; }
this.baseParams['groupBy'] = field;
}
if (this.groupOnSort) { this.sort(field); return; }
if (this.remoteGroup) { this.reload(); }
else {
var si = this.sortInfo || [];
if (si.field != field) { this.applySort(); }
else { this.sortData(field); }
this.fireEvent('datachanged', this);
}
},
applySort: function() {
var si = this.sortInfo;
if (si && si.length > 0 && !this.remoteSort) { this.sortData(si, si[0].direction); }
if (!this.groupOnSort && !this.remoteGroup) {
var gs = this.getGroupState();
if (gs && gs != this.sortInfo) { this.sortData(this.groupField); }
}
},
getGroupState: function() {
return this.groupOnSort && this.groupField !== false ? (this.sortInfo ? this.sortInfo : undefined) : this.groupField;
},
sortData: function(flist, direction) {
direction = direction || 'ASC';
var st = [];
var o;
for (var i = 0, len = flist.length; i < len; ++i) {
o = flist[i];
st.push(this.fields.get(o.field ? o.field : o).sortType);
}
var fn = function(r1, r2) {
var v1 = [];
var v2 = [];
var len = flist.length;
var o;
var name;
for (i = 0; i < len; ++i) {
o = flist[i];
name = o.field ? o.field : o;
v1.push(st[i](r1.data[name]));
v2.push(st[i](r2.data[name]));
}
var result;
for (i = 0; i < len; ++i) {
result = v1[i] > v2[i] ? 1 : (v1[i] < v2[i] ? -1 : 0);
if (result !== 0) { return result; }
}
return result; // if it gets here, that means all fields are equal
};
this.data.sort(direction, fn);
if (this.snapshot && this.snapshot != this.data) { this.snapshot.sort(direction, fn); }
}
});
Ext.ux.grid.MultiGroupingView = Ext.extend(Ext.grid.GroupingView, {
constructor: function(config) {
Ext.ux.grid.MultiGroupingView.superclass.constructor.apply(this, arguments);
// Added so we can clear cached rows each time the view is refreshed
this.on("beforerefresh", function() {
if (this.rowsCache)
delete rowsCache;
}, this);
},
get_column_by_id: function(id) {
for (i in this.cm.lookup) {
if (this.cm.lookup[i].dataIndex == id)
return this.cm.lookup[i];
}
return null;
},
getGroups: function() {
return Ext.DomQuery.select("div.x-grid-group", this.mainBody.dom);
}
, displayEmptyFields: false
, displayFieldSeperator: ', '
, renderRows: function() {
var groupField = this.getGroupField();
var eg = !!groupField;
// if they turned off grouping and the last grouped field is hidden
if (this.hideGroupedColumn) {
var colIndexes = [];
for (var i = 0, len = groupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(groupField[i]);
if (cidx >= 0) { colIndexes.push(cidx); }
}
if (!eg && this.lastGroupField !== undefined) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) { this.cm.setHidden(cidx, false); }
}
delete this.lastGroupField;
delete this.lgflen;
}
else if (eg && colIndexes.length > 0 && this.lastGroupField === undefined) {
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i)
this.cm.setHidden(colIndexes[i], true);
}
else if (eg && this.lastGroupField !== undefined &&
(groupField !== this.lastGroupField || this.lgflen != this.lastGroupField.length)) {
this.mainBody.update('');
for (var i = 0, len = this.lastGroupField.length; i < len; ++i) {
var cidx = this.cm.findColumnIndex(this.lastGroupField[i]);
if (cidx >= 0) { this.cm.setHidden(cidx, false); }
}
this.lastGroupField = groupField;
this.lgflen = groupField.length;
for (var i = 0, len = colIndexes.length; i < len; ++i) {
this.cm.setHidden(colIndexes[i], true);
}
}
}
return Ext.ux.grid.MultiGroupingView.superclass.renderRows.apply(this, arguments);
}
,
// this collection keeps a fast reference for group memberships for each record
// it is not kept in the record since it would be destroyed during edit
// it is used to do a fast update of summaries
record_memberships: []
/** This sets up the toolbar for the grid based on what is grouped
* It also iterates over all the rows and figures out where each group should appeaer
* The store at this point is already stored based on the groups.
*/
, doRender: function(cs, rs, ds, startRow, colCount, stripe) {
// var ss = this.grid.getTopToolbar();
if (rs.length < 1) { return ''; }
var groupField = this.getGroupField();
// for (var gf = 0; gf < groupField.length; gf++) {
// var fieldName = groupField[gf];
// if (fieldName == null) {
// groupField(gf).remove();
// }
// }
var gfLen = 0;
if (groupField) {
gfLen = groupField.length;
}
for (var i = 0; i < cs.length; i++)
cs[i].style = this.getColumnStyle(i, false);
// ss.removeAll();
// if (gfLen == 0)
// ss.addItem(new Ext.Toolbar.TextItem("Drop Columns Here To Group"));
// else {
// // Add back all entries to toolbar from GroupField[]
// ss.addItem(new Ext.Toolbar.TextItem("Grouped By:"));
// for (var gfi = 0; gfi < gfLen; gfi++) {
// var t = groupField[gfi];
// if (gfi >= 0) {
// ss.addItem(new Ext.Toolbar.Separator());
// var b = new Ext.Toolbar.Button({
// fieldName: t,
// text: this.get_column_by_id(t).header
// });
// ss.addButton(b);
// }
// }
// }
// ss.doLayout(); // <- is required after adding a new component - by Dalton Jorge
this.enableGrouping = !!groupField;
if (!this.enableGrouping || this.isUpdating)
return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments);
var gstyle = 'width:' + this.getTotalWidth() + ';';
var gidPrefix = this.grid.getGridEl().id;
var groups = [], curGroup, i, len, gid;
var lastvalues = [];
var added = 0;
var currGroups = [];
// Create a specific style
var st = Ext.get(gidPrefix + "-style");
if (st)
st.remove();
var html_code =
"div#" + gidPrefix +
" div.x-grid3-row {padding-left:" + (gfLen * 12) + "px}" +
"div#" + gidPrefix + " div.x-grid3-header {padding-left:" + (gfLen * 12) + "px}";
Ext.getDoc().child("head").createChild({
tag: 'style',
id: gidPrefix + "-style",
html: html_code
});
// traverse all rows in grid
for (var i = 0, len = rs.length; i < len; i++) {
added = 0;
var rowIndex = startRow + i;
var r = rs[i];
var differ = 0;
var gvalue = [];
var fieldName;
var fieldLabel;
var grpFieldNames = [];
var grpFieldLabels = [];
var v;
var changed = 0;
var addGroup = [];
var member_of_groups = [];
this.record_memberships[r.id] = member_of_groups;
// check group fields to see if we have a different group
for (var j = 0; j < gfLen; j++) {
fieldName = groupField[j];
fieldLabel = this.get_column_by_id(fieldName).header;
v = r.data[fieldName];
if (v) {
if (i == 0) {
// First record always starts a new group
addGroup.push({ idx: j, dataIndex: fieldName, header: fieldLabel, value: v });
lastvalues[j] = v;
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
}
else {
if (lastvalues[j] != v) {
// This record is not in same group as previous one
addGroup.push({ idx: j, dataIndex: fieldName, header: fieldLabel, value: v });
lastvalues[j] = v;
changed = 1;
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
}
else {
if (gfLen - 1 == j && changed != 1) {
// This row is in all the same groups to the previous group
curGroup.rs.push(r);
member_of_groups.push(curGroup);
}
else if (changed == 1) {
// This group has changed because an earlier group changed.
addGroup.push({ idx: j, dataIndex: fieldName, header: fieldLabel, value: v });
gvalue.push(v);
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ' + v);
}
else if (j < gfLen - 1) {
var parent_group = currGroups[fieldName];
// This is a parent group, and this record is part of this parent so add it
if (parent_group) {
parent_group.rs.push(r);
member_of_groups.push(parent_group);
}
}
}
}
}
else {
if (this.displayEmptyFields) {
addGroup.push({ idx: j, dataIndex: fieldName, header: fieldLabel, value: this.emptyGroupText || '' });
grpFieldNames.push(fieldName);
grpFieldLabels.push(fieldLabel + ': ');
}
}
} // end of "for j"
// build current group record
for (var k = 0; k < addGroup.length; k++) {
var gp = addGroup[k];
// if (gp.value != '') {
g = gp.dataIndex;
var glbl = addGroup[k].header;
N = this.cm.findColumnIndex(g);
var F = this.cm.config[N];
var B = F.groupRenderer || F.renderer;
var S = this.showGroupName ? (F.groupName || F.header) + ": " : "";
V = this.getGroup(gp.value, r, B, i, N, ds);
gid = gidPrefix + '-gp-' + gp.dataIndex + '-' +
Ext.util.Format.htmlEncode(gp.value);
// if state is defined use it, however state is in terms of expanded
// so negate it, otherwise use the default.
var isCollapsed = typeof this.state[gid] !== 'undefined' ?
!this.state[gid] : this.startCollapsed;
var gcls = isCollapsed ? 'x-grid-group-collapsed' : '';
curGroup = {
group: gp.dataIndex,
gvalue: V,
text: gp.header,
groupId: gid,
group_level: gp.idx,
startRow: rowIndex,
rs: [r],
cls: gcls,
style: gstyle + 'padding-left:' + (gp.idx * 12) + 'px;'
};
currGroups[gp.dataIndex] = curGroup;
groups.push(curGroup);
r._groupId = gid; // Associate this row to a group
member_of_groups.push(curGroup);
if (typeof this.groups == "undefined")
this.groups = new Array();
this.groups.push(curGroup);
// }
// else {
// gp = addGroup[k-1];
// gid = gidPrefix + '-gp-' + gp.dataIndex + '-' +
// Ext.util.Format.htmlEncode(gp.value);
// r._groupId = gid;
// }
} // end of "for k"
} // end of "for i"
var buf = [];
var parents_queued = [];
var queue_count = 0;
for (var ilen = 0, len = groups.length; ilen < len; ilen++) {
var g = groups[ilen];
// if (g.gvalue == '') {
// groups.pop();
// }
var next_group = groups[ilen + 1];
var cur_level = g.group_level;
var next_level = next_group == null ? -1 : next_group.group_level;
var leaf = g.group == groupField[gfLen - 1]
this.doGroupStart(buf, g, cs, ds, colCount);
if (g.rs.length != 0 && leaf) {
buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call(
this, cs, g.rs, ds, g.startRow, colCount, stripe);
}
if (leaf) {
// do summaries on all grouping levels for this group
this.doGroupEnd(buf, g, cs, ds, colCount);
}
else
parents_queued.push(g);
if (next_level >= cur_level)
continue;
// going back from leaf - pop parents from queue
// and call doGroupEnd for each
while (cur_level > next_level && cur_level > 0) {
g = parents_queued.pop();
this.doGroupEnd(buf, g, cs, ds, colCount);
cur_level--;
}
}
return buf.join('');
},
getGroup: function(A, D, F, G, B, E) {
var C = F ? F(A, {}, D, G, B, E) : String(A);
if (C === "")
C = this.cm.config[B].emptyGroupText || this.emptyGroupText;
return C;
},
/** Should return an array of all elements that represent a row, it should bypass
* all grouping sections
*/
getRows: function() {
if (!this.enableGrouping)
return Ext.grid.GroupingView.superclass.getRows.call(this);
return Ext.DomQuery.select("div.x-grid3-row", this.mainBody.dom);
},
getGroupById: function(gid) {
var g = null;
for (var i = 0; i < this.groups.length; i++) {
group = this.groups[i];
if (group.groupId == gid)
return group;
}
return g;
}
});
Ext.ux.grid.MultiGroupingPanelEditor = function(config) {
config = config || {};
config.tbar = new Ext.Toolbar({ id: 'grid-tbr' });
Ext.ux.grid.MultiGroupingPanelEditor.superclass.constructor.call(this, config);
};
Ext.extend(Ext.ux.grid.MultiGroupingPanelEditor, Ext.grid.GridPanel, {
isEditor: true,
detectEdit: false,
autoEncode: false,
trackMouseOver: false,
initComponent: function() {
Ext.ux.grid.MultiGroupingPanelEditor.superclass.initComponent.call(this);
if (!this.selModel) {
this.selModel = new Ext.grid.CellSelectionModel()
}
this.activeEditor = null;
this.addEvents("beforeedit", "afteredit", "validateedit")
}
, initEvents: function() {
Ext.ux.grid.MultiGroupingPanelEditor.superclass.initEvents.call(this);
this.on("bodyscroll", this.stopEditing, this, [true]);
if (this.clicksToEdit == 1) {
this.on("cellclick", this.onCellDblClick, this)
}
else {
if (this.clicksToEdit == "auto" && this.view.mainBody) { this.view.mainBody.on("mousedown", this.onAutoEditClick, this) }
this.on("celldblclick", this.onCellDblClick, this)
} this.getGridEl().addClass("xedit-grid")
}
, onCellDblClick: function(B, C, A) { this.startEditing(C, A) }
, onAutoEditClick: function(C, B) {
if (C.button !== 0) { return }
var E = this.view.findRowIndex(B);
var A = this.view.findCellIndex(B);
if (E !== false && A !== false) {
this.stopEditing();
if (this.selModel.getSelectedCell) {
var D = this.selModel.getSelectedCell();
if (D && D.cell[0] === E && D.cell[1] === A) { this.startEditing(E, A) }
}
else { if (this.selModel.isSelected(E)) { this.startEditing(E, A) } }
}
}
, onEditComplete: function(B, D, A) {
this.editing = false;
this.activeEditor = null;
B.un("specialkey", this.selModel.onEditorKey, this.selModel);
var C = B.record;
var F = this.colModel.getDataIndex(B.col);
D = this.postEditValue(D, A, C, F);
if (String(D) !== String(A)) {
var E = {
grid: this,
record: C,
field: F,
originalValue: A,
value: D,
row: B.row,
column: B.col,
cancel: false
};
if (this.fireEvent("validateedit", E) !== false && !E.cancel) {
C.set(F, E.value);
delete E.cancel;
this.fireEvent("afteredit", E);
}
}
this.view.focusCell(B.row, B.col)
}
, startEditing: function(F, B) {
this.stopEditing();
if (this.colModel.isCellEditable(B, F)) {
this.view.ensureVisible(F, B, true);
var C = this.store.getAt(F);
var E = this.colModel.getDataIndex(B);
var D = {
grid: this,
record: C,
field: E,
value: C.data[E],
row: F,
column: B,
cancel: false
};
if (this.fireEvent("beforeedit", D) !== false && !D.cancel) {
this.editing = true;
var A = this.colModel.getCellEditor(B, F);
if (!A.rendered)
A.render(this.view.getEditorParent(A));
(function() {
A.row = F;
A.col = B;
A.record = C;
A.on("complete", this.onEditComplete, this, { single: true });
A.on("specialkey", this.selModel.onEditorKey, this.selModel);
this.activeEditor = A;
var G = this.preEditValue(C, E);
A.startEdit(this.view.getCell(F, B), G);
}).defer(50, this);
}
}
}
, preEditValue: function(A, B) { return this.autoEncode && typeof value == "string" ? Ext.util.Format.htmlDecode(A.data[B]) : A.data[B] }
, postEditValue: function(C, A, B, D) { return this.autoEncode && typeof C == "string" ? Ext.util.Format.htmlEncode(C) : C }
, stopEditing: function(A) { if (this.activeEditor) { this.activeEditor[A === true ? "cancelEdit" : "completeEdit"]() } this.activeEditor = null }
, setUpDragging: function() {
this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
ddGroup: "grid-body"
, panel: this
, scroll: false
, onInitDrag: function(e) {
var clone = this.dragData.ddel;
clone.id = Ext.id('ven');
this.proxy.update(clone);
return true;
}
, getDragData: function(e) {
var target = Ext.get(e.getTarget().id);
if (target.hasClass('x-toolbar x-small-editor')) { return false; }
d = e.getTarget().cloneNode(true);
d.id = Ext.id();
this.dragData = {
repairXY: Ext.fly(target).getXY(),
ddel: d,
btn: e.getTarget()
};
return this.dragData;
}
, getRepairXY: function() { return this.dragData.repairXY; }
});
this.dropTarget2s = new Ext.dd.DropTarget('grid-tbr', {
ddGroup: "gridHeader" + this.getGridEl().id
, panel: this
, notifyDrop: function(dd, e, data) {
var btname = this.panel.getColumnModel().getDataIndex(this.panel.getView().getCellIndex(data.header));
this.panel.store.groupBy(btname);
return true;
}
});
this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
ddGroup: "grid-body"
, panel: this
, notifyDrop: function(dd, e, data) {
var txt = Ext.get(data.btn).dom.innerHTML;
var tb = this.panel.getTopToolbar();
var bidx = tb.items.findIndexBy(function(b) {
return b.text == txt;
}, this);
if (bidx < 0) return false;
var fld = tb.items.get(bidx).fieldName;
Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
if (bidx > 0) Ext.removeNode(Ext.getDom(tb.items.get(bidx - 1).id)); ;
var cidx = this.panel.view.cm.findColumnIndex(fld);
if (cidx < 0) { }
this.panel.view.cm.setHidden(cidx, false);
var temp = [];
for (var i = this.panel.store.groupField.length - 1; i >= 0; i--) {
if (this.panel.store.groupField[i] == fld) {
this.panel.store.groupField.pop();
break;
}
temp.push(this.panel.store.groupField[i]);
this.panel.store.groupField.pop();
}
for (var i = temp.length - 1; i >= 0; i--) { this.panel.store.groupField.push(temp[i]); }
if (this.panel.store.groupField.length == 0) { this.panel.store.groupField = false; }
this.panel.store.fireEvent('datachanged', this);
return true;
}
});
}
});
Ext.reg("editorgrid", Ext.ux.grid.MultiGroupingPanelEditor);
//Ext.ux.grid.MultiGroupingPanel = function(config) {
// config = config || {};
// config.tbar = new Ext.Toolbar({ id: 'grid-tbr' });
// Ext.ux.grid.MultiGroupingPanel.superclass.constructor.call(this, config);
//};
//Ext.extend(Ext.ux.grid.MultiGroupingPanel, Ext.grid.GridPanel, {
// initComponent: function() {
// Ext.ux.grid.MultiGroupingPanel.superclass.initComponent.call(this);
// this.on("render", this.setUpDragging, this);
// }
// , setUpDragging: function() {
// this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
// ddGroup: "grid-body"
// , panel: this
// , scroll: false
// , onInitDrag: function(e) {
// var clone = this.dragData.ddel;
// clone.id = Ext.id('ven');
// this.proxy.update(clone);
// return true;
// }
// , getDragData: function(e) {
// var target = Ext.get(e.getTarget().id);
// if (target.hasClass('x-toolbar x-small-editor')) {
// return false;
// }
// d = e.getTarget().cloneNode(true);
// d.id = Ext.id();
// this.dragData = {
// repairXY: Ext.fly(target).getXY(),
// ddel: d,
// btn: e.getTarget()
// };
// return this.dragData;
// }
// , getRepairXY: function() { return this.dragData.repairXY; }
// });
// this.dropTarget2s = new Ext.dd.DropTarget('grid-tbr', {
// ddGroup: "gridHeader" + this.getGridEl().id
// , panel: this
// , notifyDrop: function(dd, e, data) {
// var btname = this.panel.getColumnModel().getDataIndex(this.panel.getView().getCellIndex(data.header));
// this.panel.store.groupBy(btname);
// return true;
// }
// });
// this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
// ddGroup: "grid-body"
// , panel: this
// , notifyDrop: function(dd, e, data) {
// var txt = Ext.get(data.btn).dom.innerHTML;
// var tb = this.panel.getTopToolbar();
// var bidx = tb.items.findIndexBy(function(b) {
// return b.text == txt;
// }, this);
// if (bidx < 0) return false;
// var fld = tb.items.get(bidx).fieldName;
// Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
// if (bidx > 0) Ext.removeNode(Ext.getDom(tb.items.get(bidx - 1).id)); ;
// var cidx = this.panel.view.cm.findColumnIndex(fld);
// if (cidx < 0) { }
// this.panel.view.cm.setHidden(cidx, false);
// var temp = [];
// for (var i = this.panel.store.groupField.length - 1; i >= 0; i--) {
// if (this.panel.store.groupField[i] == fld) {
// this.panel.store.groupField.pop();
// break;
// }
// temp.push(this.panel.store.groupField[i]);
// this.panel.store.groupField.pop();
// }
// for (var i = temp.length - 1; i >= 0; i--) { this.panel.store.groupField.push(temp[i]); }
// if (this.panel.store.groupField.length == 0) { this.panel.store.groupField = false; }
// this.panel.store.fireEvent('datachanged', this);
// return true;
// }
// });
// }
//});
Ext.ux.grid.MultiGroupingGrid = function(config) {
config = config || {};
// Cache the orignal column model, before state is applied
if (config.cm)
this.origColModel = Ext.ux.grid.clone(config.cm.config);
else if (config.colModel)
this.origColModel = Ext.ux.grid.clone(config.colModel.config);
// config.tbar = [{
// xtype: 'tbtext'
// , text: this.emptyToolbarText
// }, {
// xtype: 'tbfill'
// , noDelete: true
// }, {
// xtype: 'tbbutton'
// , text: 'Options'
// , noDelete: true
// , menu: {
// items: [{
// text: 'Columns Reset',
// scope: this,
// disabled: !this.origColModel,
// handler: function() {
// this.getColumnModel().setConfig(this.origColModel, false);
// this.saveState();
// return true;
// }
// }, {
// text: 'Show columns grouped'
// , checked: !config.view.hideGroupedColumn
// , scope: this
// , checkHandler: function(item, checked) {
// this.view.hideGroupedColumn = !checked;
// this.view.refresh(true);
// }
// }, {
// text: 'Clean filters' // Labels.get('label.jaffa.jaffaRIA.jaffa.finder.grid.deactivateFilters')
// , scope: this
// , handler: function() {
// //@TODO use the clearFilters() method!
// this.plugins.filters.each(function(flt) {
// flt.setActive(false);
// });
// }
//}]
// }
//}];
Ext.ux.grid.MultiGroupingGrid.superclass.constructor.call(this, config);
//console.debug("Create MultiGroupingGrid",config);
};

//Ext.extend(Ext.ux.MultiGroupingGrid, Ext.grid.GridPanel, {
//modified by jesus, extend a Ext.grid.EditorGridPanel class
Ext.extend(Ext.ux.grid.MultiGroupingGrid, Ext.grid.EditorGridPanel, {

initComponent: function() {
//console.debug("MultiGroupingGrid.initComponent",this);
Ext.ux.grid.MultiGroupingGrid.superclass.initComponent.call(this);
// Initialise DragZone
// this.on("render", this.setUpDragging, this);
}
/** @cfg emptyToolbarText String to display on tool bar when there are no groups
*/
, emptyToolbarText: "Drag the columns to group here"
/** Extend basic version so the Grouping Columns State is remebered
*/
, getState: function() {
var s = Ext.ux.grid.MultiGroupingGrid.superclass.getState.call(this);
s.groupFields = this.store.getGroupState();
return s;
}
/** Extend basic version so the Grouping Columns State is applied
*/
, applyState: function(state) {
Ext.ux.grid.MultiGroupingGrid.superclass.applyState.call(this, state);
if (state.groupFields) {
this.store.groupBy(state.groupFields, true);
if (typeof console != "undefined")
console.debug("Grid.applyState: Groups=", state.groupFields);
}
}
// , setUpDragging: function() {
// //console.debug("SetUpDragging", this);
// this.dragZone = new Ext.dd.DragZone(this.getTopToolbar().getEl(), {
// ddGroup: "grid-body" + this.getGridEl().id //FIXME - does this need to be unique to support multiple independant panels on the same page
// , panel: this
// , scroll: false
// // @todo - docs
// , onInitDrag: function(e) {
// // alert('init');
// var clone = this.dragData.ddel;
// clone.id = Ext.id('ven'); //FIXME??
// // clone.class='x-btn button';
// this.proxy.update(clone);
// return true;
// }
// // @todo - docs
// , getDragData: function(e) {
// var target = Ext.get(e.getTarget().id);
// //console.debug("DragZone: ",e,target);
// if (!target || target.hasClass('x-toolbar x-small-editor')) {
// return false;
// }
// d = e.getTarget().cloneNode(true);
// d.id = Ext.id();
// if (typeof console != "undefined")
// console.debug("getDragData", this, target);
// this.dragData = {
// repairXY: Ext.fly(target).getXY(),
// ddel: d,
// btn: e.getTarget()
// };
// return this.dragData;
// }
// //Provide coordinates for the proxy to slide back to on failed drag.
// //This is the original XY coordinates of the draggable element.
// , getRepairXY: function() {
// return this.dragData.repairXY;
// }
// });
// // This is the target when columns are dropped onto the toolbar (ie added to the group)
// this.dropTarget2s = new Ext.dd.DropTarget(this.getTopToolbar().getEl(), {
// ddGroup: "gridHeader" + this.getGridEl().id
// , panel: this
// , notifyDrop: function(dd, e, data) {
// if (this.panel.getColumnModel().config[this.panel.getView().getCellIndex(data.header)].groupable) {
// if (typeof console != "undefined")
// console.debug("Adding Filter", data);
// var btname = this.panel.getColumnModel().getDataIndex(this.panel.getView().getCellIndex(data.header));
// this.panel.store.groupBy(btname);
// return true;
// }
// else {
// return false;
// }
// }
// , notifyOver: function(dd, e, data) {
// if (this.panel.getColumnModel().config[this.panel.getView().getCellIndex(data.header)].groupable) {
// return this.dropAllowed;
// }
// else {
// return this.dropNotAllowed;
// }
// }
// });
// // This is the target when columns are dropped onto the grid (ie removed from the group)
// this.dropTarget22s = new Ext.dd.DropTarget(this.getView().el.dom.childNodes[0].childNodes[1], {
// ddGroup: "grid-body" + this.getGridEl().id //FIXME - does this need to be unique to support multiple independant panels on the same page
// , panel: this
// , notifyDrop: function(dd, e, data) {
// var txt = Ext.get(data.btn).dom.innerHTML;
// var tb = this.panel.getTopToolbar();
// if (typeof console != "undefined")
// console.debug("Removing Filter", txt);
// var bidx = tb.items.findIndexBy(function(b) {
// if (typeof console != "undefined")
// console.debug("Match button ", b.text);
// return b.text == txt;
// }, this);
// if (typeof console != "undefined")
// console.debug("Found matching button", bidx);
// if (bidx < 0) return false; // Error!
// var fld = tb.items.get(bidx).fieldName;
// // Remove from toolbar
// Ext.removeNode(Ext.getDom(tb.items.get(bidx).id));
// if (bidx > 0) Ext.removeNode(Ext.getDom(tb.items.get(bidx - 1).id)); ;
// if (typeof console != "undefined")
// console.debug("Remove button", fld);
// //console.dir(button);
// var cidx = this.panel.view.cm.findColumnIndex(fld);
// if (cidx < 0)
// console.error("Can't find column for field ", fld);
// this.panel.view.cm.setHidden(cidx, false);
// //Ext.removeNode(Ext.getDom(data.btn.id));
// // Remove this group from the groupField array
// // @todo - replace with method on store
// // this.panel.store.removeGroupField(fld);
// var temp = [];
// for (var i = this.panel.store.groupField.length - 1; i >= 0; i--) {
// if (this.panel.store.groupField[i] == fld) {
// this.panel.store.groupField.pop();
// break;
// }
// temp.push(this.panel.store.groupField[i]);
// this.panel.store.groupField.pop();
// }
// for (var i = temp.length - 1; i >= 0; i--) {
// this.panel.store.groupField.push(temp[i]);
// }
// if (this.panel.store.groupField.length == 0)
// this.panel.store.groupField = false;
// this.panel.store.fireEvent('datachanged', this);
// return true;
// }
// });
// }
, buildFilters: function(columns, record) {
//console.debug("Grid.buildFilters: Created Filters from ", columns, record);
var config = [];
for (var i = 0; i < columns.length; i++) {
var col = columns[i];
var meta = record.getField(col.dataIndex);
//console.debug("Meta Data For ", col.dataIndex, meta)
if (meta && (meta.filter || meta.filterFieldName)) {
var dt = meta.dataType || 'string';
if (dt == 'int' || dt == 'long' || dt == 'float' || dt == 'double')
dt == 'numeric';
else if (dt == 'dateonly' || dt == 'datetime')
dt = 'date';
//FIXME pass caseType on this filter definition, so it can be applied to the filter field
var f = { dataIndex: col.dataIndex, type: dt, paramName: col.filterFieldName };
config[config.length] = f;
}
}
if (typeof console != "undefined")
console.debug("Grid.buildFilters: Created Filters for ", config);
if (config.length == 0)
return null;
else
return new Ext.ux.grid.GridFilters({ filters: config, local: false });
}
, buildColumnModel: function(columns, record) {
var config = [];
for (var i = 0; i < columns.length; i++) {
var col = columns[i];
var meta = record.getField(col.dataIndex);
var cm = Ext.apply({}, col);
if (meta) {
// Apply stuff from the Record's Meta Data
if (!cm.hidden && meta.hidden == true) cm.hidden = true;
if (!cm.header && meta.label) cm.header = meta.label;
if (!cm.renderer && meta.renderer) cm.renderer = meta.renderer;
cm.sortable = (meta.sortable === true || (meta.sortFieldName && meta.sortFieldName != ''));
// Apply more metadata from associated ClassMetaData
var mc = meta.metaClass || record.defaultMetaClass;
var mfn = (meta.mapping || col.dataIndex).match(/.*\b(\w+)$/)[1];
var mf = ClassMetaData[mc] ? ClassMetaData[mc].fields[mfn] : undefined;
if (!mf) mf = ClassMetaData[mc] ? ClassMetaData[mc].fields[col.dataIndex] : undefined;
if (typeof console != "undefined")
console.debug("Meta Class=", mc, ClassMetaData[mc], ', dataIndex=', col.dataIndex, ', mapping=', meta.mapping, ', mfn=', mfn, ', mf=', mf, ', meta=', meta);
if (mf) {
// Default the header text
if (!cm.header && mf.label) cm.header = mf.label;
// Default the column width
if (!cm.width) {
if (mf.maxLength) cm.width = Math.min(Math.max(mf.maxLength, 5), 40) * 8;
else if (mf.type) {
if (mf.type == 'dateonly') cm.width = 100;
else if (mf.type == 'datetime') cm.width = 140;
else if (mf.type == 'boolean') cm.width = 50;
}
}
// Default the alignment
if (!cm.align && mf.type && (mf.type == 'float' || mf.type == 'int'))
cm.align = 'right';
// Default standard renderers
if (!cm.renderer && mf.type) {
if (mf.type == 'dateonly') cm.renderer = Ext.util.Format.dateRenderer();
else if (mf.type == 'datetime') cm.renderer = Ext.util.Format.dateTimeRenderer();
}
if (mf.hidden == true) cm.hidden = true;
}
}
if (!cm.header) cm.header = col.dataIndex;
cm.groupable = (cm.groupable == true || cm.sortable == true);
config[config.length] = cm;
if (typeof console != "undefined")
console.debug("Grid.buildColumnModel: Width", cm.dataIndex, cm.width);
}
if (typeof console != "undefined")
console.debug("Grid.buildColumnModel: Created Columns for ", config);
return new Ext.grid.ColumnModel(config);
}
});
Ext.ux.grid.MultiGroupingPagingGrid = Ext.extend(Ext.ux.grid.MultiGroupingGrid, {
/** When creating the store, register an internal callback for post load processing
*/
constructor: function(config) {
config = config || {};
config.bbar = [].concat(config.bbar);
config.bbar = config.bbar.concat([
{ xtype: 'tbfill' }
, { xtype: 'tbtext', id: 'counter', text: '? of ?' }
, { xtype: 'tbspacer' }
, { xtype: 'tbbutton', id: 'loading', hidden: true, iconCls: "x-tbar-loading" }
, { xtype: 'tbseparator' }
, { xtype: 'tbbutton', id: 'more', text: '>>', handler: function() { this.store.loadMore(false); }, scope: this }
]);
Ext.ux.grid.MultiGroupingPagingGrid.superclass.constructor.apply(this, arguments);
// Create Event that asks for more data when we scroll to the end
this.on("bodyscroll", function() {
var s = this.view.scroller.dom;
if ((s.offsetHeight + s.scrollTop + 5 > s.scrollHeight) && !this.isLoading) {
if (typeof console != "undefined")
console.debug("Grid.on.bodyscroll: Get more...");
this.store.loadMore(false);
}
}, this);
// When the grid start loading, display a loading icon
this.store.on("beforeload", function(store, o) {
if (this.isLoading) {
if (typeof console != "undefined")
console.debug("Store.on.beforeload: Reject Load, one is in progress");
return false;
}
this.isLoading = true;
if (this.rendered) {
this.barLoading.show();
}
if (typeof console != "undefined")
console.debug("Store.on.beforeload: options=", o, this);
return true;
}, this);
// When loading has finished, disable the loading icon, and update the row count
this.store.on("load", function() {
delete this.isLoading;
if (this.rendered) {
this.barLoading.hide();
if (typeof console != "undefined")
console.debug("Store.on.load: Finished loading.. ", this.store.totalCount);
this.barCounter.getEl().innerHTML = "Mostrando " + this.store.getCount() + ' de ' +
(this.store.totalCount ? this.store.totalCount : '?');
if (this.store.totalCount)
this.barMore.disable();
else
this.barMore.enable();
}
return true;
}, this);
// When a loading error occurs, disable the loading icon and display error
this.store.on("loadexception", function(store, e) {
if (typeof console != "undefined")
console.debug("Store.loadexception.Event:", arguments);
delete this.isLoading;
if (this.rendered) {
this.barLoading.hide();
}
if (e)
Ext.Msg.show({
title: 'Show Details',
msg: "Error cargando registros - " + e,
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return false;
}, this);
// As the default onLoad to refocus on the first row has been disabled,
// This has been added so if a load does happen, and its an initial load
// it refocuses. If this is a refresh caused by a sort/group or a new page
// of data being loaded, it does not refocus
this.store.on("load", function(r, o) {
if (o && o.initial == true)
Ext.ux.grid.MultiGroupingView.superclass.onLoad.call(this);
}, this.view);
}
// private
, onRender: function(ct, position) {
Ext.ux.griMultiGroupingPagingGrid.superclass.onRender.call(this, ct, position);
var bb = this.getBottomToolbar();
this.barCounter = bb.items.itemAt(bb.items.length - 5);
this.barMore = bb.items.itemAt(bb.items.length - 1);
this.barLoading = bb.items.itemAt(bb.items.length - 3);
}
});


I have also attached the jpgs as what i m getting currently and how i wanted. as you can see in asNeeded.jpg I removed the extra header thro firebug. but i want its functionality.

mrbeig9
15 Dec 2009, 8:43 AM
Hi all,

Thanks for the great plugin. I am new to Extjs I need help in removing the groupHeader if there is no value in the Groupfield. I have attached jpg files which describe how it is now and how i want it. I need some changes in the plugin. any help would be greatly appreciated.

Thanks

nestore2k
19 Jan 2010, 5:47 PM
Hi, Can anyone help me with the Multigrouping grid? I was working with a grouping store and a gropingview in a EditorGridPanel and with that I could get the info sorted by the DB with the remoteSort option in the GroupingStore, but now I need to use Multi level grouping in my grid but I can´t stop using my EditorGridPanel. I changed my store and my view for the Ext.ux.MultiGroupingStore and the Ext.ux.MultiGroupingView using the Multigrouping.js posted before!

My question is Can I sort the info from the DB for all the grid pages not for each one using something like the remoteSort option in the Ext.data.GroupingStore?

Helton Gon
8 Feb 2010, 6:22 AM
Friends,

Anybody knows anything similar to this project but for GXT? I think everyone would appreciate if this become part of core of ExtJS and GXT to... Do you aggree? /:)

At this time, I am working in trying to do this for GXT. :((

Congratulations Jaffa!!

maquejp
11 Mar 2010, 12:24 AM
Any chance to have a stable final version? (compatible with 3.1.1)

Haron
12 Mar 2010, 4:49 AM
Hi there, according to Helton post, we developed an gxt extension to make severel levels of grouping on the Grid.

Here are the classes needed.

amsoft
19 Mar 2010, 3:32 AM
Hi!
It's really useful extension! Thanks! But I have such a question. If I have to group data by two fields, but one of them are the same these fields are duplicated. I'll try to explain on the following example:


var colModel = new Ext.grid.ColumnModel([
{header: 'Group', dataIndex: 'group', hidden: true, width:50, sortable: true},
{header: 'SubGroup', dataIndex: 'subgroup', hidden: true, width:150},
{header: 'SomeData', dataIndex: 'someData', width:150},
]);

var dummyData = [
['GROUP1','SUBGROUP1', 'DummyData1'],
['GROUP1','SUBGROUP1', 'DummyData2'],
['GROUP2','SUBGROUP2', 'DummyData3'],
['GROUP2','SUBGROUP1', 'DummyData4']
];

var reader = new Ext.data.ArrayReader({}, [
{name: 'group'},
{name: 'subgroup'},
{name: 'someData'}
]);

var groupStore = new Ext.ux.MultiGroupingStore({
reader: reader,
data: dummyData,
groupField: ['group','subgroup'],
sortInfo: {field: 'group', direction: 'DESC'}
});
var groupView = new Ext.ux.MultiGroupingView({
forceFit: true,
emptyGroupText: 'All Group Fields Empty',
displayEmptyFields: true,
groupTextTpl: '{text} ',
displayFieldSeperator: ', '
});

this.gridPanel = new Ext.grid.GridPanel({
title: 'Test MG',
frame: true,
collapsible: true,
autoHeight: true,
store: groupStore,
cm: colModel,
view: groupView,
renderTo: Ext.getBody()
});

As a result we'll have the following output:
group: GROUP1
--subgroup: SUBGROUP1
---DummyData1
---DummyData2
---DummyData4 --this data is duplicated. It has nothing to do here because refers to GROUP2 and should be grouped only sub GROUP2

group: GROUP2
--subgroup: SUBGROUP1
---DummyData4
--subgroup: SUBGROUP2
---DummyData3

Is it bug or I'm doing something wrong here?

alexpotemkin
27 Apr 2010, 2:45 AM
Simple question - Why? What i doing wrong.
My code for grid:


Ext.ns('Backend.gridpoints');

var pointsDataRecord = Ext.data.Record.create([
{name: 'id_point', type: 'int', mapping: 'id_point', sortable:true},
{name: 'id_group', type: 'int', mapping: 'id_group', sortable:true},
{name: 'name_group', type: 'string', mapping: 'name_group', sortable:true},
{name: 'name_point', type: 'string', mapping: 'name_point', sortable:true},
{name: 'address_point', type: 'string', mapping: 'address_point', sortable:true},
{name: 'id_city', type: 'int', mapping: 'id_city', sortable:true},
{name: 'name_city', type: 'string', mapping: 'name_city', sortable:true},
{name: 'id_region', type: 'int', mapping: 'id_region', sortable:true},
{name: 'name_region', type: 'string', mapping: 'name_region', sortable:true},
{name: 'desc_point', type: 'string', mapping: 'desc_point'},
{name: 'x_gmap_point', type: 'float', mapping: 'x_gmap_point'},
{name: 'y_gmap_point', type: 'float', mapping: 'y_gmap_point'},
{name: 'images_folder_point', type: 'string', mapping: 'images_folder_point'},
{name: 'icon_group', type: 'string', mapping: 'icon_group'}
]);

var pointsColModel = new Ext.grid.ColumnModel([
{header: 'Код', dataIndex: 'id_point', sortable:true},
{header: 'Код группы', dataIndex: 'id_group', sortable:true},
{header: 'Группа', dataIndex: 'name_group', sortable:true},
{header: 'Наименование', dataIndex: 'name_point', sortable:true},
{header: 'Адрес', dataIndex: 'address_point', sortable:true},
{header: 'Город', dataIndex: 'name_city', sortable:true},
{header: 'Код области', dataIndex: 'id_region', sortable:true},
{header: 'Область', dataIndex: 'name_region', sortable:true},
{header: 'Комментарий', dataIndex: 'desc_point'},
{header: 'X', dataIndex: 'x_gmap_point'},
{header: 'Y', dataIndex: 'y_gmap_point'},
{header: 'Папка изображений', dataIndex: 'images_folder_point'}
]);

var pointsDataReader = new Ext.data.JsonReader({root: 'results'}, pointsDataRecord);

var pointsDataProxy = new Ext.data.HttpProxy({url: 'backend/js_listPoints', method: 'POST'});

var pointsDataStore = new Ext.ux.grid.MultiGroupingStore({
proxy: pointsDataProxy,
reader: pointsDataReader,
sortInfo: {field: 'id_point', direction: 'ASC'},
groupField: ['name_region','name_city','name_group']
});

var pointsGroupView = new Ext.ux.grid.MultiGroupingView({
hideGroupedColumn:true,
emptyGroupText: 'В данной группе записи отсутсвуют',
displayEmptyFields: true,
groupTextTpl: '{text} : {group}'
});

Backend.gridpoints = new Ext.ux.grid.MultiGroupingGrid({
initComponent:function() {
Ext.apply(this, {
store:pointsDataStore,
cm:pointsColModel,
view:pointsGroupView,
id: 'grid_points',
enableColumnMove:false,
viewConfig:{forceFit: true},
sm: new Ext.grid.RowSelectionModel({singleSelect:true}),
bbar: new Ext.PagingToolbar({store: pointsDataStore, pageSize:150, displayInfo:true})
});

this.on({
afterlayout:{scope:this, single:true, fn:function() {
pointsDataStore.load({params:{start:0, limit:10}});
}},
afterrender: function(component) {
component.getBottomToolbar().refresh.hideParent = true;
component.getBottomToolbar().refresh.hide();
}
});

Backend.gridpoints.superclass.initComponent.apply(this, arguments);
} // eo function initComponent
});

Ext.reg('gridpoints', Backend.gridpoints);

rupidas
3 May 2010, 11:23 PM
Hi,
I am using a multi level grouping grid, which will be loaded on constant intervals. Initially the grid is rendered fine. But after subsequent refreshes the grouping disappears. attached some screen shots.

The error that was captured from firebug is
Error in ext-all-debug.js file
r is undefined
[Break on this error] p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds) ;

Any help??

Kunha
31 May 2010, 3:53 AM
Hi all,

can some one point me to a way to print this kind of grid :)

i can access data from Grid object but cant find information about grouping.

thanks

print.js


//GET GROUPS
var view = grid.view;
var groupField = view.getGroupField();
var r = [];
var g, gs = view.getGroups();


//GetGrupos e linhas
r = view.getRowsFromGroup2(r, gs, groupField[0]);


multigroupingview.js



,getRowsFromGroup2: function(r, gs, lsField){
var rx = new RegExp(".*-gp-"+lsField+"-.*");
var str = Ext.util.Format;

// Loop over each section
for (var i = 0; i < gs.length; i++)
{
//title SECÇÃO
var nomeGrupo = "";
//console.debug("Grupo "+nomeGrupo);

if (gs[i].childNodes[0])
{
//Body secção
g = gs[i].childNodes[0].childNodes;
//console.debug(groupName, " matched ", lsField);

var rows = "";
if ( gs[i].childNodes[0].className == "x-grid3-row-table") {
rows = g;
console.debug("Linha "+g);
}
else
nomeGrupo = Ext.util.Format.stripTags(gs[i].childNodes[0].childNodes[0].innerHTML);

r[r.length] = {
grupo: nomeGrupo,
linha: rows
};
}

if (gs[i].childNodes[1])
{
// if its an interim level, each group needs to be traversed as well
r = this.getRowsFromGroup2(r, gs[i].childNodes[1].childNodes, lsField);
}
}
return r;
}

thorben
17 Jun 2010, 11:20 AM
Hello,

thank you for this component. This is exactly what we've been looking for.

Nevertheless, we are experiencing problems with Ext 3.2 (Firefox 3.6.3, Windows 7): When we upload the example page to our site, the following javascript error occurs: "Ext.fly(rows[0]) is null" (ext-all-debug.js, line 43959). This is the processRows method of the grid. However, all data are loaded from orders.json and displayed properly. Column resizing does not work, though.

Is this a general problem with Ext 3.2.1, or is there any known solution to this problem?

paivajose
14 Jul 2010, 12:03 PM
I have the same problem but only when testing in IE 7 and 8. Any solution ?

krishnaswamy
20 Jul 2010, 12:39 PM
Hi
This is an amazing discussion and great work from all the guys, hats off, but i am trying to find a single place to get the latest version of this plugin, please help me, my requreimnet was simeple, multiple column grouping n Editable - no summary

krishnaswamy
20 Jul 2010, 8:32 PM
Hi ExtJs gurus,
I am 2 days old in working with extjs, the first task itself is Editable Multi grouping Paged Grid.
I followed this thread and i am not quite sure about which version of MultiGrouping.js i should use.
further even after setting the editor i am not getting editable grid



{
header: 'Family Name'
,width: 100
,dataIndex: 'familyName'
,sortable: true
,editor: new Ext.form.TextField({
allowBlank: false
})
Aslo the table controls in group top tool bar and bottom tool bar buttons are not showing right
I am trying hard to make this work, I have demo tomorrow!!
I added the paging tool bar but no matter what page size i set it show all in 1 page :(

rogerio.carrasqueira
13 Sep 2010, 5:56 AM
Hi Everybody!

I'm following this discussion about the MultiGrouping Grid and I need to solve a simple point on my implementation. Where I can disable the top bar where appear the buttons "Group By"?

I've tried to just add the parameter buildTopToolbar, but it not worked.

Can anyone help with this?

Thanks,

Rogério Carrasqueira


var siteGrid = new Ext.ux.MultiGroupingPanelEditor ({
store: siteStore,
columns: siteColumns,
view: siteView,
height: 450,
frame: true,
title: 'Mapa do Site',
renderTo: 'site-grid',
buildTopToolbar : function() {
return [{
text: 'Novo Usuário',
handler: this.onAdd,
scope: this
}, '-', {
text: 'Excluir Usuário',
handler: this.onDelete,
scope: this
}, '-'];
}

});

jaquet
14 Sep 2010, 1:48 AM
Hi all,

I am using the MultiGrouping grid in a project, but I have a problem when adding a selection model. I am trying to add the checkbox selection model. But when I use it, I get an error on the multigrouping.js:

this.get_column_by_id(t) is null.

Did anybody add a checkbox selection model to this grid already? What am I doing wrong?

Erik-Jan

jdamani
30 Sep 2010, 11:13 AM
Hi all,
I am using ExtJS 3.2.0.

Multigrouping grid demo is great. I was looking for such feature. I have downloaded code from
http://jaffa.cvs.sourceforge.net/viewvc/jaffa/JaffaRIA/source/html/?diff_format=h

I am getting error : Exception: too much recursion File: http://127.0.0.1:8000/multiproject/WebContent/scripts/ux/utils/DeepClone.js Line: 19 Column: 0

Can anyone help ???

Thanks in advance

sergeiw
16 Oct 2010, 12:50 AM
I tried debugging with firebug and it appears that Ext 3.2+ adds a property 'scope' with value 'this' each column definition of the column model. Since DeepClone traverses each property cloning recursively it enters in an infinite recursion over the first column.

I don't know if this is the best way, but I added a check for the property value to be different from the object we are cloning to avoid infinite recursion. This is on line 19 of DeepClone.js


Ext.ux.clone = function(o){
if (!o || 'object' !== typeof o) {
return o;
}
if ('function' === typeof o.clone) {
return o.clone();
}
var c = 'function' === typeof o.pop ? [] : {};
var p, v;
for (p in o) {
if (o.hasOwnProperty(p)) {
v = o[p];
if (v && 'object' === typeof v && v != o) {
c[p] = Ext.ux.clone(v);
}
else {
c[p] = v;
}
}
}
return c;
}; // eo function clone

This made the trick for me, and MultiGroupingGrid is now working great. I hope it works for you to.

karimchebani
8 Nov 2010, 7:48 AM
For Ext 3.3 users please this thread can be usefull : http://www.sencha.com/forum/showthread.php?110217-MultiGroupingPanel-on-Ext-3.3-beta&highlight=Multiple+level+grouping

cristinadelosa
23 Nov 2010, 4:54 AM
anybody knows if this extension will work on 3.3??

garrythebest
23 Nov 2010, 9:12 AM
Don't work with Extjs 3.3. X(
You need to use Extjs 2.3.

mosull2
19 Jan 2011, 1:39 AM
Hi. I am using GWT ExtGXT in a java web app. Has anyone developed been able to develop multi level grouping using java as apposed to JS?

thanks

yyogev
30 Jan 2011, 2:42 AM
Hi,

See my fix here:
http://www.sencha.com/forum/showthread.php?110217-MultiGroupingPanel-on-Ext-3.3-beta&p=547422&viewfull=1#post547422

Manjula
1 Feb 2011, 5:47 PM
Hi,

I have taken the zip files but when I open the html page on the browser(firefox or IE),a blank page is displayed.
whether this works on the server or locally it can work?
Please tell me the process of how to make it work

yyogev
1 Feb 2011, 9:34 PM
Hi,

I have taken the zip files but when I open the html page on the browser(firefox or IE),a blank page is displayed.
whether this works on the server or locally it can work?
Please tell me the process of how to make it work

A blank page means you either have a syntax error in your JavaScript code, or a run time error.
The first thing you can do is look in the browser JavaScript console for any syntax errors. If all is well, use a JS debugger to find the problem. I recommend using the Firebug debugger extension in Firefox.

If you want to use ExtJS, this is something you MUST master.

Good luck

tdikarim
26 Apr 2011, 6:14 AM
Hi,
Anyone know how to apply the grouping store after a load definition via metadata

Thanks