Flex them Grids! (AdvancedDataGrid as a subgrid with flat data)
A grid inside a grid is a common requirement; I thought. Yet, I scoured the internet for a solution and I couldn’t find it anywhere (…at least not something that could be done with “flat data”). The following is something I wanted to achieve.Adobe LiveDocs show an example here http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7bf2.html where they put a chart in an itemrenderer. However they show this example with “Hierarchical” collection. Their data structure looks like:
1: [Bindable]
2: private var dpHierarchy:ArrayCollection= new ArrayCollection([
3: {name:"Barbara Jennings", region: "Arizona", total:70, children:[
4: {detail:[{amount:5},{amount:10},{amount:20},{amount:45}]}]},
5: {name:"Dana Binn", region: "Arizona", total:130, children:[
6: {detail:[{amount:15},{amount:25},{amount:35},{amount:55}]}]},
7: {name:"Joe Smith", region: "California", total:229, children:[
8: {detail:[{amount:26},{amount:32},{amount:73},{amount:123}]}]},
9: {name:"Alice Treu", region: "California", total:230, children:[
10: {detail:[{amount:159},{amount:235},{amount:135},{amount:155}]}
11: ]}
12: ]);
However, this is almost never how one would get data from the server. We generally get a flat data-structure as ArrayCollection. The the trick would be to convert this flat structure into a Hierarchy of objects.
1: private var _BaseData:ArrayCollection = new ArrayCollection([
2: {region:'south', state:'FL', city:'Alachua', population:'6,098'},
3: {region:'south', state:'FL', city:'Alford', population:'466'},
4: {region:'south', state:'FL', city:'Altha', population:'506'},
5: {region:'south', state:'FL', city:'Altamonte', population:'41,200'},
6: {region:'south', state:'TX', city:'Addison', population:'14,166'},
7: {region:'south', state:'TX', city:'Perezville', population:'5,444'},
8: {region:'south', state:'TX', city:'Alamo', population:'14,760'},
9: {region:'north', state:'NY', city:'Airmont', population:'7,799'},
10: {region:'north', state:'NY', city:'Akron', population:'3,085'},
11: {region:'north', state:'NY', city:'Alabama', population:'1,881'},
12: {region:'north', state:'NY', city:'Albany', population:'95,658'}
13: ]);
1: private var _HData:ArrayCollection = new ArrayCollection([
2: {region:'south', state:'FL', children:[{detail:[
3: {city:'Alachua', population:'6,098'},
4: {city:'Altamonte', population:'41,200'},
5: {city:'Alford', population:'466'},
6: {city:'Altha', population:'506'}
7: ]}
8: ]},
9: {region:'south', state:'TX', children:[{detail:[
10: {city:'Perezville', population:'5,444'},
11: {city:'Addison', population:'14,166'},
12: {city:'Alamo', population:'14,760'}
13: ]}
14: ]},
15: {region:'north', state:'NY', children:[
16: {detail:[
17: {city:'Airmont', population:'7,799'},
18: {city:'Akron', population:'3,085'},
19: {city:'Alabama', population:'1,881'},
20: {city:'Albany', population:'95,658'}
21: ]
22: }
23: ]}
24: ]);
The following function uses a cursor to iterate over this ArrayCollection, read the city and population, creates a child object. Then it discards the repeated rows.
public function setHierarchy():void {
// sort first
var sort:Sort= new Sort();
sort.fields = [new SortField('state',false)];
_BaseData.sort = sort;
_BaseData.refresh();
var HData:ArrayCollection = new ArrayCollection();
var csr:IViewCursor = _BaseData.createCursor();
var previousState:String = "";
var counter:int = 0;
var children:Array = [];
while(!csr.afterLast) {
// flag to remove repeated rows
var addToHierarchy:Boolean = false;
var subGridObj:Object = {city:'',population:''};
subGridObj.city = csr.current.city;
subGridObj.population = csr.current.population;
// find next/previous values and compare with current record
var str:String = csr.current.state;
if (previousState != str) {
children = [];
previousState = str;
// flag to remove repeated rows
addToHierarchy = true;
}
//create child objects and populate with child-data
children.push(subGridObj);
csr.current.children = [];
csr.current.children[counter] = {detail:children};
// copy to Hierarchy and neglect repeated rows
if (addToHierarchy) {
HData.addItem(csr.current);
}
csr.moveNext();
}
// finally make assignment as HierarchicalData
adg1.dataProvider = new HierarchicalData(HData);
}
The AdvancedDataGrid declaration should now take an ItemRenderer column
<mx:AdvancedDataGrid id="adg1" x="200" width="600" height="400" variableRowHeight="true"
verticalCenter="0">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Region" dataField="region" />
<mx:AdvancedDataGridColumn headerText="State" dataField="state" />
</mx:columns>
<mx:rendererProviders>
<mx:AdvancedDataGridRendererProvider
dataField="detail"
renderer="subGridRenderer"
columnSpan="0" columnIndex="1"/>
</mx:rendererProviders>
</mx:AdvancedDataGrid>
and the itemrenderer would be composed of a grid:
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<s:VGroup paddingBottom="10" paddingLeft="10" paddingTop="10">
<mx:AdvancedDataGrid id="subAdg" dataProvider="{data.detail}">
</mx:AdvancedDataGrid>
</s:VGroup>
</s:MXAdvancedDataGridItemRenderer>
2 comments:
Techie,
This is very useful. Basically we have to reorganize data
Love the Kramer pic on your blog. Nicely done..
Post a Comment