Rendezvous with technology

Preserving the open nodes in AdvancedDataGrid after re-grouping

Posted on: November 19, 2008

Consider a scenario in which you want to group some data and display it in an AdvancedDataGrid. Now, you open some nodes. And you want to add summaries to the data. Adding summaries means to re-group the data by calling GroupingCollection.refresh(). But the state of open nodes will be lost as new Objects are created for the group nodes while re-grouping.

I’m posting a sample in which the open nodes are preserved.

Sample here.

Source here.

Open the sample, click on Group data, open some nodes and then click on Add Summary. The nodes which are open will remain open.

Basically, here I’m giving the same UID for the group nodes as they were before (re-grouping). That’s why, the open state is maintained.

Note: This sample will work only if the grouping fields are same for both groupings. It’ll need some tweaking in case the grouping fields are changed.

About these ads

64 Responses to "Preserving the open nodes in AdvancedDataGrid after re-grouping"

Hi Sameer,

Iam using advanced DataGrid in which my data provider is a group collection.I am also using SummaryRow which is placed at “group” level. Now my Client wants that Initial sort order should be desecending based on SummaryRow. I have also used label function for summaryRow.I am able to sort data by my custom sort function but i dont know how to initially sort the based on summaryRow.
I tried sorting underlying FlatDataProvider but that is not working.
My summaryRow contains Financial Data like $145,45,89.
Pleae help its urgent….
Thanks in advance.

If the SummaryField’s label is same as the dataField of the column in which the summary is shown, you can sort the grid by summary without much hassle.
Make sure you follow these steps –

adg.dataProvider = gc; // assign the GroupingCollection
adg.validateNow(); // call validateNow()
adg.dataProvider.sort = sort; // assign the sort
adg.dataProvider.refresh();

Hi Sameer,

Thanks for the suggestion it worked.
One more thing I want to sort the column which contains the grouped data .As suggested by you iam using
g.label=d2[h].label
gf = new GroupingField();
gf.name = d2[h].label;
g.fields.push(gf);
where g is my grouping and gf is grouping field,but iam still not able to sort my grouping column.It is just sorting the data inside the group(data under various groups) but group order remains the same.

Thanks in advance.

Hi sameer,
I need ur help again.I using a group collection to display my data in the grid.
Now my requirement is whenever user selects ne node in the grid i need to show the content of that node in a pie chart or a pie chart corresponding to the content of the node.

How can i get the selected node from the group collection.

Thanks in advance.

AdvancedDataGrid.selectedItem property will give you the selected node.

This example might help you –
http://flexpearls.blogspot.com/2007/09/displaying-charts-in-advanceddatagrid.html

hi Sameer.
I’m confused. In documentation I found the next description of property selectedIndex:
The index in the data provider of the selected item.

In dataProvider I have just one record. But in the ADG this record is on the second position, cause the first show me the group.
When I’m clicking on the non grouping item, the selectedIndex property come as 1, not as 0.
Can you tell me why and how can I get the right selectedIndex, the index of selected item the dataProvider, in my case in ArrayCollection.

Thanks in advance!

You are using GroupingCollection to group the items. Now, the dataProvider of the AdvancedDataGrid is the GroupingCollection containing the grouped item also.
So, the first item is the grouped item at index 0 and the non-grouped item is at index 1.
You can get the selectedItem and find its position in the source that you provided to the GroupingCollection.

Hi Sameer,
I have an advanceddatagrid and have to open few nodes when its created. Please see my code below. I’m getting the first trace and not getting the second one. Whats the problem with my ‘IHierarchicalCollectionViewCursor’ declaration? My adg is getting created. Thanks in advance.

private function createGrid():void{
adg = new ADGbgColor();
adg.rowCount = totalRows
adg.groupedColumns = createColumns
hd = new HierarchicalData()
hd.source = myXML.elements()
adg.dataProvider = hd

adg.horizontalScrollPolicy = ScrollPolicy.AUTO
adg.lockedColumnCount=1
this.addChild(adg);
var dh:HierarchicalCollectionView = adg.dataProvider as
HierarchicalCollectionView;
trace(“======coming here”)
var cursor:IHierarchicalCollectionViewCursor = dh.createCursor()
as IHierarchicalCollectionViewCursor
trace(cursor.currentDepth+”====end”)
}

call adg.validateNow(); after this.addChild(adg);

Thanks Sameer, it works fine now!

Hi Sameer,

Is there a way to make cells clickable and pass information of the cells in the row to a new component opened up?

I noticed that cellSelectionData hash table is private in AdvancedDataGrid and there doesn’t seem to be a way of directly accessing all of its contents.

Any pointer/help will be appreciated.

-Thanks

set selectionMode=”singleCell”. You can get the row index and column index of the selected cell using adg.selectedCells property.
Get the item in the dataProvider corresponding to the selected row/column.

Hello, one more time, Sameer!
And one more question i have.
I have 2 ADGs, that are using as dataProvider one ArrayCollection but very large. Now, in this situation, I need to synchronize the navigation for this 2 ADGs. The selectedItem I’ve already done. Now I’m trying to do the same with the groupItem on expand and collapse. I get the AdvancedDataGridEvent on itemOpening and itemClose. After that I’m not sure what to do next. What I need is to get the Index of the groupItem in the active for this moment ADG and to translate the state to the second ADG’s groupItem. Maybe the way is not correct and its not necessary to listen the itemOpening and itemClose events.
Help!
Thanks in advance! Good luck.

If I understand correctly, you want to synchronize the opening and closing of the items in the two grids. If you open an item in the first grid, it should reflect in the second one and vice-versa.
To do this, just make sure that both the grids have the same dataProvider. For example, if you have two grids adg1 and adg2 and you have assigned GroupingCollection to adg1.dataProvider.
Then, assign adg1’s dataProvider to adg2’s dataProvider after grouping is done. –

gc.refresh(); // call refresh
adg1.validateNow(); // validate, let the dataProvider to be set
adg2.dataProvider = adg1.dataProvider as IHierarchicalCollectionView; // assign the dataProvider

This works because both the grids are using the same instance of dataProvider (IHierarchicalCollectionView).

Thanks a lot, Sameer!!!

Hi Sameer,

My ADG collapses when I apply filters and I need it to expand all nodes that
were opened before.

I tried something like this :

var openNodes:Object = IHierarchicalCollectionView(adg.dataProvider).openNodes;
hd.source = myXML.elements()
adg.dataProvider = hd
adg.validateNow()
IHierarchicalCollectionView(adg.dataProvider).openNodes = openNodes

But it doesn’t work.
How can I solve this problem?

Having a uid property in the xml nodes may resolve your issue.
How are you applying filters here?

applying filters to the xml and assigning the xml again to the datagrid.

Can you post a simple sample of what you are trying to do?

I would like to export the visible items in my adg with grouping to excel…It seems somewhat similar to the functionality you have here…

Ideally I would loop through either the ADG and build a table using the visible items (or expanded nodes, summary nodes) or use the grouping collection…

But I am not sure about the syntax…Any help would be greatly appreciated…

If you just need the open nodes, use –
var openNodes:Object = IHierarchicalCollectionView(adg.dataProvider).openNodes;

Go through the openNodes variable and do whatever you want.

Thanks for your timely response…

I haven’t worked with IHierarchicalCollectionView or OpenNodes before so forgive me if I do not know all the syntax…

The Header section works perfectly as it is based only on the adg…But the details are not showing up in excel…I am sure my syntax in wrong…

Here are the relevant pieces of my code

var adg:AdvancedDataGrid = dgBase as AdvancedDataGrid;
var openNodes:Object = IHierarchicalCollectionView(adg.dataProvider).openNodes;

for(var j:int =0;j<openNodes.numChildren;j++) {
str+=””;

for(var k:int=0; k < adg.columns.length; k++) {
if(adg.columns[k].labelFunction != undefined) {
str += “”+adg.columns[k].labelFunction(openNodes.getItemAt(j),adg.columns[k].dataField)+””;

} else {
str += “”+openNodes.getItemAt(j)[adg.columns[k].dataField]+””;
}
}

str += “”;
str+=””;
}

Thoughts?

The HTML tags where stripped out of my last message
lines with str+= “”; should have html table tags inside

Hi wpageiii,

I just saw ur post reg export to excel functionality for the grouped data in adg. I am also facing the same issue. Can u just reply me how u resolved that issue and able to get data in the excel.

Thanks in advance

hey rekha,
I am looking for the same feature. where you able to solve it. if so can you please help me with it.

thanks a lot :)

So, openNodes does not have any numChildren property. You can iterate over it using the for-each loop like –
for each (var item:* in openNodes)
{
// do things here
}
Also, there is no property like getItemAt() in openNodes. Its an Object.
In the above loop, item will be having all the properties.
Try debugging it to see what’s inside it.
Let me know if you face any issues.

Sameer, thanks for the helpful tutorial! Can you help me get the value of the label on the grouped items? I am using this code but it returns nothing in the Alert window.

private function adg_itemClick(e:ListEvent, adg:AdvancedDataGrid):void{
var item:Object = AdvancedDataGrid(e.currentTarget).selectedItem;
adg.expandItem(item, !adg.isItemOpen(item), true);
Alert.show(item.label.text);
}

Use item["GroupLabel"] to get the label.
Also you can set a custom label by setting Grouping.label property while creating the GroupingCollection.

Hi Sameer,

Can you tell me how to get the value of item.GroupingField?
When I select an item, I want to know the groupingfield of that item.

Thanks a Lot

mshetty

Thanks for your answer Sameer! That worked well!

Manasa, are you looking for the value/label of the groupingField that you click on? I think you can use this code to get what you’re looking for…

add the itemClick to your AdvancedDataGrid…

and this function….
private function adg_itemClick(e:ListEvent, adg:AdvancedDataGrid):void{
var item:Object = AdvancedDataGrid(e.currentTarget).selectedItem;
adg.expandItem(item, !adg.isItemOpen(item), true);
Alert.show(item["GroupLabel"]);
}

If I reload the data for the datagrid from the server the code doesn’t work :(

private function handleGetApplicationData(event:ResultEvent):void
{
vo.tradesResult=event.result.DEALS as ArrayCollection;
if (deals.dataProvider != null)
{
var openNodes:Object=IHierarchicalCollectionView(deals.dataProvider).openNodes;
gcTrades.refresh();
setupSlider();
deals.dataProvider=gcTrades;
deals.validateNow();

IHierarchicalCollectionView(deals.dataProvider).openNodes=openNodes;
}
else
{
gcTrades.refresh();
setupSlider();
deals.dataProvider=gcTrades;
}
}

Are you setting up the UID for the group nodes just like I’ve shown in the sample?

Hi Sameer,
i have similar problem for remembering the open nodes of advanced datagrid .i m very new to this tool .By going through ur post and these suggestion i tried to do it own but couln,t succeed.So could u pls help me if u have any relevent code for this here i will just detail my problem.

Actually i have to save the state of my Advanced datagrid as if one row is opened it should be opened once the user is logged in agin.Maens if i checked for two rows and log out and once wil be back these two nodes should be remain open. How can i do it with my web application. As how can i save state for every user .

Thanks

You can use SharedObject to store the open nodes for a particular user. Also, make sure to set up the UID as shown in the sample.

Hi sameer ,
once i got the open node value say in arraycollection .
how to save that in shared object and again how can i populate the same based on value for open nodes .
pls suggest me or any reference code .

I need to do different grouping for each level in the tree, the user will right click on the icon and select which grouping is relevant for the specific level, is it possible?

Do you mean multiple level of Grouping?
Which icon should the user right click for selecting the grouping?

Hi sameer

Hi sameer,

Same mentioned issue.I have adg with hierrarchical data.I am keeping the opennodes XML when making the server call.But not able to open with expandItem(previous XML) .What could be wrong.Thanks in advance

So, the two xmls are different. You need to have a unique property in your xml. Try these steps –
1. Add a new property – lets say uid which is unique for every item. You can change it to any property which you think will be unique.
2. Since the item fetched from the Server will be different from the items already present. Find an item in the already existing items which has the same uid as that of the item you got from the Server. Now expand the item.

Hi Sameer,
What ever I do the values from the Array ddArr does not get populated in the PopUPMenu Button.
I have an advanced data grid , with 8 columns one of the columns i want the 8 th column as a POPUPMenu Button, and when I click on the menu item it should navigate to a url value which is in the Array dArr. Array dArr has 2 values ,how can i do this I have tried many things.
Array dArr has the values [dd.label,dd.url] and some valuses in the array has more than one occurence, I mean [dd.label1,dd.url1],[dd.label2,dd.url2].
The values to be populated in the POPUPMenuButton , i have in an array ddArr.
please help me out.

.hStyle { fontWeight:bold; fontFamily:Verdana; fontSize:12; align:center; }

0 )
{

ddLabel= ddRest.substring( 0, ddidx );

ddRest= ddRest.substring(ddidx + 1 );
ddidx = ddRest.indexOf(“|”);
if( ddidx > 0)
{
// ddUrl= ddRest.substring(ddidx + 1 );
ddUrl= ddRest.substring(0, ddidx );

ddRest= ddRest.substring(ddidx + 1 );
ddidx = ddRest.indexOf(“|”);
}

dObj.label= ddLabel;
dObj.url= ddUrl;
ddArr.addItem(dObj);

}
popUpB=new PopUpMenuButton();
myMenu = new Menu();
myMenu.labelField = “Action”;
myMenu.showRoot = true;
myMenu.width = popUpB.width;
myMenu.selectedIndex = 0;
myMenu.dataProvider = ddArr;

// myMenu.addEventListener(“itemClick”, itemClickHandler);

popUpB.popUp = myMenu;

dp.addItem( { “Index”:xd[0], “Service”:xd[1], “Priority”:xd[2], “Current SLA”:xd[3],”Health”:xd[4], “Quality”:xd[5],
“Risk”:xd[6], “Avail”:xd[7], “OpMode”:xd[8], “dd”:popUpB} );
dp = dpSrv;
gc.source=dp;
gc.refresh();

]]>

<!– –>

<!– –>

thanks in advance,
Tom.

I don’t think I got your issue. Can you explain a little more.
A simple sample will help.

Hi Sameer,
I have flat data and am grouping it in AdvancedDataGrid. My problem is when I filter the data, all the open nodes are being collapsed. When I open a node and filter the data, I should be able to preserve the open node.
This is what I did.
1) Fetch openNodes into “nodes”
2) Filter function
3) Refresh the groupingcollection
4) datagrid.validateNow();
5) IHierarchicalCollectionView(datagrid.dataProvider).openNodes = null;

I am still loosing the open nodes :(

I would really appreciate your help in this regards

Thanks

5) IHierarchicalCollectionView(datagrid.dataProvider).openNodes = nodes;

Are you using the approach that I’ve shown in the above post – using the same UID for the group nodes as they were before (re-grouping).

Thanks a lot !!!!…. The collapsing behavior is no more present !!!

Hi, I have a ADG loading data from Remote Objects. There are several grouping fields and summary fields for each group. I am using the Grouping groupingObjectFunction=”grpObjFunc” to create unique ids (uid: value + count++).

The problem occurs when I have some open nodes and refresh the dataprovider, reassigning the open nodes works correctly, however the children of the open nodes are not the correct ones.

The me see If I can explain, lets say I have groups like this, (in my case 3 levels, where level 2 and 3 for groups in group 1.eg.

G1 – Sales 2008
G2 – New York
G3 Route A
Children Data
G2 – Seattle
G3 Route C
Children Data

G1 – Sales 2009
G2 – New York
G3 Route A
Children Data
G2 – Seattle
G3 Route C
Children Data

I think if all groups exist there is no problem. My problem occurs when I have say :

G1 – Sales 2008
G2 – New York
G3 Route A
Children Data
G2 – Seattle
G3 Route C
Children Data

G1 – Sales 2009
G2 – Seattle
G3 Route C
Children Data

New York is missing in the above chart from sales 2009. Now if Seatle is open and I get new data with NewYork grouping, the datagrid refreshes with Seatle open (which is correct) but the data in New York is from other groups as well as NewYork Data. Quite strange. Any ideas as to why?

The data is changing and the openNodes assigned are the old copy, thats why old data is shown. The best way to solve this is to create new openNodes object when the new data comes. This can be done by iterating through the old openNodes Object and finding the node in the new collection with the same UID and creating the openNodes object.

Hi Sameer,

Thankyou for the timely response. I thought I might have to do somthing like that. However when debugging I have noticed that the following uids get appied to the nodes.:

Before data load:

G1 – Sales 2008 Sales 20081
G2 – Seattle Seattle2
G3 Route C Route C3
Children Data

After

G1 – Sales 2008 Sales 20081
G2 – New York New York2
G3 Route A Route A3
Children Data
G2 – Seattle Seattle4
G3 Route C Route C5
Children Data

My Objects dont have there own uids (from the server) they are created by grpObj Function.

As you can see the uids are not the same for the old open nodes. How can I know if the node is open if the id is no longer present?

Would creating unique uids on the server solve this problem?

If the items have unique uids (from the server) do I still need to specify a groupingObjectFunction?

Thanks again.

David

Sameer,

We are using advancedatagrid and groupcollection with hirarchicaldata for tree structure. On every refresh event we are fetching same tree structure with updated data from RPC call. We are using your logic of storing openNode for previous datagrid and assigning them to new datagrid. Here in actionscript we are using expandItem() for every open node. Our logic is iterating all open nodes properly and might be expanding all nodes in actionscript but when they get displayed through mxml, they get become cllapsible a root node itself. Please advice us what we need to do for display open nodes as it is in refresh mode. Our code logic is as:

vMLocator.static_XMLString = new HierarchicalData(vMLocator.dashboard_Static_Table_List.getItemAt(1,0));
vMLocator.groupID.source = vMLocator.static_XMLString;
vMLocator.groupID.refresh();
vMLocator.adg_tabularDB_month.dataProvider = vMLocator.static_XMLString;
vMLocator.adg_tabularDB_month.validateNow();
if(vMLocator.openNodes != null){
var myOpenNodes:Array = new Array();
var HierColView:HierarchicalCollectionView = HierarchicalCollectionView(vMLocator.adg_tabularDB_month.dataProvider);
for each ( var item:Object in HierColView.openNodes ) {
//vMLocator.adg_tabularDB_month.expandItem(item, true);
//var isItemOpen:Boolean=vMLocator.adg_tabularDB_month.isItemOpen(item);
myOpenNodes.push(item);
};
IHierarchicalCollectionView(vMLocator.adg_tabularDB_month.dataProvider).openNodes = myOpenNodes;

One way to do it in the groupingObjectFunction is when you are assigning uid to the new nodes, you can check if the uid is present in the old open nodes that you’ve saved. If it is present, then save this object in the new open nodes object.
Later assign the new open nodes to the collection.

While if you create uids on the server, you don’t need to use groupingObjectFunction but whenever you are assigning the open nodes, you have to make sure that your openNodes object contains the nodes from the new collection.

Also, your uid generation algorithm should be consistent and produce the same uid for similar nodes.

Hi Sameer,

I created a getter in my childVO object ‘get uid’, that returned the groupname + year + user + date.time as the unique id.

removing the grouping function caused the nodes to return closed after a data reload.

I then put the grouping function back in and returned a new object with the new uid of the current node. This caused Flash to hang with a script timeout when open the node to show the children.

I then added the count++ to the new uid that the grouping function returned. When the data changed the nodes closed…

Perhaps the option of “One way to do it in the groupingObjectFunction is when you are assigning uid to the new nodes, you can check if the uid is present in the old open nodes that you’ve saved. If it is present, then save this object in the new open nodes object.
Later assign the new open nodes to the collection.”

Do you have an example of that or where I can start looking?

Kind Regards, and Thank you for you help.

David

I wrote a very simple example showing what I meant. Can you mail me here prosameer [at] gmail [dot] com so that I can send you the sample.

Hi,

I am trying to reopen nodes which were previously opened in AdvancedDataGrid with updated data provider. My dataprovider is a XML. So output should be same open node structure with updated data.

private function restoreNodes():void{
var myXml1:XML = //some updated XML

myXml=myXml1.copy();

Alert.show(“updated xml:” +myXml);

for each ( var item:Object in opItems) {
myOpenNodes.push(item);
//Alert.show(“Open Items: “+item.toString());

}

hd=new HierarchicalData(myXml);
adg.dataProvider=hd;
adg.dataProvider.refresh();
for each ( var item1:Object in myOpenNodes ) {
Alert.show(“inside for”);
var dataCursor:IHierarchicalCollectionViewCursor =
adg.dataProvider.createCursor();
dataCursor.seek(CursorBookmark.FIRST);

while (!dataCursor.afterLast){
Alert.show(“Item label”+dataCursor.current.toString());
if (dataCursor.current.GroupLabel == item1.GroupLabel) {
//Alert.show(“inside if”);
adg.expandItem(dataCursor.current, true,true);
}
dataCursor.moveNext();
}
}
}

This is the logic i am using to restore nodes with earlier open nodes with updated data.

This is working to some extent but not 100%.
Please give some solution regarding the same.
Anyhelp is appreciated.

Thnaks,
Yogesh

A sample with xml that I created long back is located here

hi Sameer,
I have a similar problem,
I can not reopen before the nodes open a query in my AdvancedDataGrid, I show you the code:

myOpenNodes = IHierarchicalCollectionView(tabellaOrdini.dataProvider).openNodes;

searchOrdini();

tabellaOrdini.dataProvider = richiestaGroup;
tabellaOrdini.validateNow();

IHierarchicalCollectionView(tabellaOrdini.dataProvider).openNodes = myOpenNodes;

I tried with invalidateList () and others,
with a Cursor….

thanks in advance

Are you using the approach that I’ve shown in the above blog post – using the same UID for the group nodes as they were before (re-grouping). Also, I’ve posted a sample using xml data in the post above (# 41)

hi,
I have an Advanced DataGrid with Grouping where I need to update data
every 20 seconds.

On a DataGrid I update the ArrayCollection, I refresh the
ArrayCollection and validate the datagrid.

On an AdvancedDataGrid I know you also need to refresh the
GroupingCollection, how would I display the changed data WITHOUT
losing the open Nodes on the GroupingCollection?? It doesn’t make
sense to keep closing the nodes and to expandAll() takes too long.

Thanks in advance.

Actually, you don’t need to refresh() the GroupingCollection everytime the data is changed if the Objects are Bindable. The GroupingCollection will take care of updating things if the data changes. For that, you can use ObjectProxy instead of Object in your ArrayCollection or manually call the ICollectionView.itemUpdated() method with the right values. For more details, have a look at this post

Hi Vikram, regarding your query in post #32, I’ve posted a sample with xml in reply to post #41.

this seems to work

var openNodes:Array = new Array();

for (var s:String in GV.dataProvider.openNodes) {
var o:Object = GV.dataProvider.openNodes[s];
openNodes.push(o.GroupLabel);
}

groupedData.refresh();
GV.dataProvider.openNodes = null;

var dp:Object = GV.dataProvider;
var cursor:IViewCursor = dp.createCursor();

while( !cursor.afterLast ) {
for (var i:int=0;i<openNodes.length;i++) {
if (openNodes[i] == cursor.current.GroupLabel) {
GV.expandItem(cursor.current,true);
}
}
cursor.moveNext();
}

Philip, your solution is the only one I found so far it is working !
Thanks a lot.

I only had to change the following line from:

if (openNodes[i] == cursor.current.GroupLabel) {

to:

if (cursor.current.hasOwnProperty(“GroupLabel”) && openNodes[i] == cursor.current.GroupLabel) {

hi Sameer,
I have an adv. DataGrid and its dataprovider is hierarchialData, initially the grid must show all the nodes open, hence i have used the property
displayItemsExpanded=”true”, further when the user collapse a node , i have to maintain its state for the next data refresh().
Another problem is i can not use GroupingCollection coz i have used an itemrenderer for my grid whish implements BaseListData, so if i try your earlier mentioned approach then it is giving me corretion failed error.
Pls tell me any approach to maintain collapse state of nodes.
Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: