The enhancements to the data grids in Flex 3 have been eagerly anticipated, and are greatly appreciated - especially by us ColdFusion developers who spend so much time creating highly data-centric applications. I plan on providing examples of how to use the new data grids with ColdFusion, and here is the first.
AdvancedDataGrid supports group expanding and collapsing within grids, think of it as a grid with an embedded tree control. Multiple levels of grouping are supported (each level becomes a tree branch), but this example uses a single level for simplicity's sake.
The example uses the default database tables that come with ColdFusion 8, and here is the simple CFC method which just returns several columns from two tables:
<cfcomponent>
<cffunction name="getArtByMedia" access="remote" returntype="query">
<cfset var result="">
<cfquery datasource="cfartgallery" name="result">
SELECT mediatype, artname, description, price
FROM media, art
WHERE media.mediaid=art.mediaid
ORDER BY mediatype, artname
</cfquery>
<cfreturn result>
</cffunction>
</cfcomponent>
I saved this component as art.cfc in a folder named test beneath the web root. You can save it wherever you like, but of course you'll need to adjust the path in the MXML accordingly. Here is the MXML:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" width="100%" height="100%"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
// Init
public function initApp():void
{
// Get data
svc.getArtByMedia();
}
]]>
</mx:Script>
<!-- Define CFC -->
<mx:RemoteObject id="svc"
destination="ColdFusion" source="test.Art"
result="gc.refresh()" />
<!-- The grid -->
<mx:AdvancedDataGrid width="100%" height="100%">
<!-- Define grouping in dataProvider -->
<mx:dataProvider>
<mx:GroupingCollection id="gc" source="{svc.getArtByMedia.lastResult}">
<mx:Grouping>
<mx:GroupingField name="MEDIATYPE" />
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<!-- The grid columns -->
<mx:columns>
<mx:AdvancedDataGridColumn dataField="MEDIATYPE"
headerText="Media"/>
<mx:AdvancedDataGridColumn dataField="ARTNAME"
headerText="Name" />
<mx:AdvancedDataGridColumn dataField="DESCRIPTION"
headerText="Description" />
<mx:AdvancedDataGridColumn dataField="PRICE"
headerText="Price" textAlign="right" />
</mx:columns>
</mx:AdvancedDataGrid>
</mx:Application>
<mx:RemoteObject> points to the CFC. <mx:AdvancedDataGrid> defines the grid and columns, in much the same way as regular <mx:DataGrid> does. But unlike <mx:DataGrid>, here the dataProvider is passed as a child tag so as to be able to specify additional information. <mx:AdvancedDataGrid> can accept hierarchical data ready to be used for grouping, as well as flat data, in which case a GroupingCollection must be used so that Flex can regroup the data hierarchically. As ColdFusion queries are flat (non-hierarchical), a GroupingCollection is defined using <mx:GroupingCollection>. The GroupingCollection accepts one or more fields to be grouped on, and here a single field is specified using <mx:GroupingField>.
When using GroupingCollections like this, the data grid itself must explicitly be refreshed so that the changes are reflected in the displayed grid. According to the documentation, this example would do this as <mx:AdvancedDataGrid ... initialize="gc.refresh()">, but this does not seem to work. Instead, the refresh() method is specified in <mx:RemoteObject> so that it is called when data is received. (Thanks to Mike Nimer for figuring this one out for me!).
And there you have it, a really simple data grid with expand/collapse grouping.
I've been having this refresh issue and it's driving me crazy. I call a webservice on my main flex application page, but I can't get my container to refresh unless I use a button ... please help! The code is below to help anyone else with this issue (I deleted items from the code to make it more readable).
By the way ... Ben I've been reading your stuff for years but this is the first time I post.
Joe S.
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:v="views.dashboard.*"
layout="horizontal"
creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.collections.SortField;
import mx.collections.Sort;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
[Bindable]
public var selectedItem:Object;
[Bindable]
public var selectedSite:String = "";
/* [Bindable]
public var selectedType:String = "Select a Site"; */
[Bindable]
public var mselectedType:String = "Select Function";
[Bindable]
public var rselectedType:String = "Select Region";
/* [Bindable]
private var categories:ArrayCollection=new ArrayCollection(); */
[Bindable]
private var mcategories:ArrayCollection=new ArrayCollection();
[Bindable]
private var rcategories:ArrayCollection=new ArrayCollection();
/* private function catHandler(event:ResultEvent):void{
categories = event.result.catalog.category;
var catObj:Object = new Object();
catObj.name = "Select a Site";
catObj.categoryID = 0;
categories.addItemAt(catObj, 0);
catCombo.selectedIndex = 0;
} */
private function mcatHandler(event:ResultEvent):void{
mcategories = event.result.masteroptions.mcategory;
var mcatObj:Object = new Object();
mcatObj.mname = "Select Function";
mcatObj.mcategoryID = 0;
mcategories.addItemAt(mcatObj, 0);
mcatCombo.selectedIndex = 0;
}
private function rcatHandler(event:ResultEvent):void{
rcategories = event.result.regionoptions.rcategory;
var rcatObj:Object = new Object();
rcatObj.rname = "Select Region";
rcatObj.rcategoryID = 0;
rcategories.addItemAt(rcatObj, 0);
rcatCombo.selectedIndex = 0;
}
//SITES
private function salesRPCResult(event:ResultEvent):void{
sales.dp = (event.result as ArrayCollection);
}
private function activityRPCResult(event:ResultEvent):void{
activity.dp = (event.result as ArrayCollection);
}
private function demandRPCResult(event:ResultEvent):void{
demand.dp = (event.result as ArrayCollection);
}
//SITE ADDITIONAL
private function bldgIDRPCResult(event:ResultEvent):void{
bldgID.dp = (event.result as ArrayCollection);
}
private function EVPRPCResult(event:ResultEvent):void{
evpDetails.dp = (event.result as ArrayCollection);
}
private function bldgTypeRPCResult(event:ResultEvent):void{
bldgType.dp = (event.result as ArrayCollection);
}
private function bldgRPCResult(event:ResultEvent):void{
bldg.dp = (event.result as ArrayCollection);
}
private function showFault(event:FaultEvent):void{
trace(event.fault.faultCode+":"+event.fault.faultString);
}
private function getFunctionData():void{
//FUNCTIONAL
dashboardWS.getFunctionRFTDetails.send();
dashboardWS.getFunctionHLMCDetails.send();
dashboardWS.getFunctionHLMCINTLDetails.send();
}
private function getRegionData():void{
//REGIONAL
dashboardWS.getRegionalUtilization.send();
dashboardWS.getCapitalSpend.send();
dashboardWS.getGlobalUtilizationUSINTLChart.send();
//SUBREGIONAL
dashboardWS.getSubRegionalUtilization.send();
dashboardWS.getSubCapitalSpend.send();
dashboardWS.getSubRegionalUtilizationChart.send();
dashboardWS.getSubRegionalDemand.send();
}
private function getSiteData():void{
//SITES
dashboardWS.getSalesData.send();
dashboardWS.getActivityData.send();
dashboardWS.getDemandsupplyData.send();
//SITE ADDITIONAL
dashboardWS.getBldgIDData.send();
dashboardWS.getEVPData.send();
dashboardWS.getBldgTypeData.send();
dashboardWS.getBldgData.send();
}
private function getData():void{
//GLOBAL
dashboardWS.getGlobalUtilization.send();
dashboardWS.getGlobalUtilizationUSChart.send();
dashboardWS.getGlobalUtilizationINTLChart.send();
//SUMMARIES
dashboardWS.getMasterDetails.send();
dashboardWS.getFunctionDetails.send();
/* OTHER
dashboardWS.getMasterUtilization.send();
dashboardWS.getMasterUtilizationNAMA.send();
dashboardWS.getMasterUtilizationEU.send();
dashboardWS.getMasterUtilizationAPLA.send(); */
}
private function init():void{
// startDate.selectedDate = new Date(2006,3,1);
// endDate.selectedDate = new Date(2006,4,1);
// catRPC.send();
mcatRPC.send();
rcatRPC.send();
getData();
}
private function sortByDateField(aSales:ArrayCollection, colName:String):ArrayCollection{
var salesData:ArrayCollection = aSales;
var sort:Sort = new Sort();
sort.fields = new Array(new SortField(colName,true));
salesData.sort = sort;
salesData.refresh();
return salesData;
}
/* private function setCat(event:Event):void{
selectedType = ComboBox(event.currentTarget).selectedItem.categoryID;
getData();
} */
private function msetCat(event:Event):void{
mselectedType = ComboBox(event.currentTarget).selectedItem.mcategoryID;
getFunctionData();
}
private function rsetCat(event:Event):void{
rselectedType = ComboBox(event.currentTarget).selectedItem.rcategoryID;
getRegionData();
}
private function setSite(event:Event):void{
selectedSite = List(event.currentTarget).selectedItem.data;
getSiteData();
}
]]>
</mx:Script>
<mx:Model id="sitesUS">
<states>
<state label="Thousand Oaks" data="USTO"/>
<state label="San Francisco" data="USSF"/>
<state label="Fremont" data="USFM"/>
<state label="Washington; Bothell" data="USWA-BOTHELL"/>
<state label="Washington; Seattle" data="USWA-SEATTLE"/>
<state label="Colorado; Boulder" data="USBO-BOULDER"/>
<state label="Colorado; Longmont" data="USBO-LONGMONT"/>
<state label="Rhode Island" data="USRI"/>
<state label="Cambridge, MA" data="USAM"/>
<state label="Puerto Rico" data="PRJU"/>
<state label="Canada, Toronto" data="CA"/>
<state label="Canada, Burnaby" data="CABN"/>
</states>
</mx:Model>
<mx:Model id="sitesEUCEE">
<states>
<state label="Austria; CEE" data="ATVI"/>
<state label="Bulgaria" data=""/>
<state label="Czech" data="CZPR"/>
<state label="Hungary" data="HUBU"/>
<state label="Poland" data="PLWA"/>
<state label="Romania" data=""/>
<state label="Slovakia" data="SKPI"/>
<state label="Slovenia" data="SLLJ"/>
</states>
</mx:Model>
<mx:WebService
id="dashboardWS"
wsdl="http://ustositedev.amgen.com/afm/scripts/flex/aggr...;
fault="showFault(event)">
<!-- SITES -->
<mx:operation name="getSalesData" result="salesRPCResult(event)">
<mx:request>
<!-- <startDate>2006,4,1</startDate>
<endDate>2006,4,1</endDate> -->
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<mx:operation name="getActivityData" result="activityRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<mx:operation name="getDemandsupplyData" result="demandRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<!-- SITE ADDITIONAL -->
<mx:operation name="getBldgIDData" result="bldgIDRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<mx:operation name="getEVPData" result="EVPRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<mx:operation name="getBldgTypeData" result="bldgTypeRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
<mx:operation name="getBldgData" result="bldgRPCResult(event)">
<mx:request>
<category>{selectedSite}</category>
</mx:request>
</mx:operation>
</mx:WebService>
<mx:HTTPService id="mcatRPC"
url="/afm/db/flex/master_options.xml"
result="mcatHandler(event)"/>
<mx:HTTPService id="rcatRPC"
url="/afm/db/flex/region_options.xml"
result="rcatHandler(event)"/>
<mx:ApplicationControlBar dock="true">
<mx:LinkBar dataProvider="{myNav}" disabledColor="0xffffff" separatorColor="0xffffff" />
</mx:ApplicationControlBar>
<mx:ViewStack id="myNav" height="100%" width="100%" creationPolicy="all">
<mx:VBox id="allBox" label="Sites" width="100%" height="100%">
<mx:HBox id="SiteContainer" width="100%" height="100%">
<mx:Accordion id="accordion" borderStyle="solid" dropShadowEnabled="true" color="0x323232" width="15%" height="100%">
<!-- Define each panel using a VBox container. -->
<mx:VBox label="US/Canada Sites" height="100%" width="100%">
<mx:List id="sourceUS" width="100%" color="0x0050AA" dataProvider="{sitesUS.state}" height="100%"
change="this.selectedItem=List(event.target).selectedItem; setSite(event);" />
</mx:VBox>
<mx:VBox label="Europe - CEE" height="100%" width="100%">
<mx:List id="sourceEUCEE" width="100%" color="0x0050AA" dataProvider="{sitesEUCEE.state}" height="100%"
change="this.selectedItem=List(event.target).selectedItem; setSite(event);" />
</mx:VBox>
</mx:Accordion>
<mx:VBox id="allSiteContainer" width="100%" height="100%">
<mx:HBox id="siteLinkBox" width="100%">
<mx:LinkBar dataProvider="{newSiteContainer}" disabledColor="0xffffff" />
<!--<mx:Spacer width="10"/>
<mx:Label text="Selected State: {selectedItem.data}"/>-->
<mx:Spacer width="100%"/>
<mx:Text maxHeight="30">
<mx:htmlText>
<![CDATA[
<font color="#EE1122"> Utilization > 90% </font> <font color="#ffffff">|</font> <font color="#EE1122"><b>Utilization > 100% </b></font>
]]>
</mx:htmlText>
</mx:Text>
</mx:HBox>
<mx:ViewStack id="newSiteContainer" height="100%" width="100%" creationPolicy="all">
<mx:VBox id="vboxSiteContainer" label="Utilization and Activity" width="100%" height="100%">
<v:Utilization id="sales" width="100%" height="100%" title="Utilization"
maximize="this.currentState='fullSales'" restore="this.currentState=''"/>
<mx:HBox id="rightCharts" width="100%" height="100%" >
<v:Activity id="activity" width="100%" height="100%" title="Site Activity"
maximize="this.currentState='fullType'" restore="this.currentState=''"/>
<v:UtilizationYear id="demand" width="100%" height="100%" title=" Demand vs Capacity"
maximize="this.currentState='fullComp'" restore="this.currentState=''"/>
</mx:HBox>
</mx:VBox>
<mx:VBox id="allSecondBox" label="Capacity Details" width="100%" height="100%">
<v:BuildingDetails id="bldgID" title="Building Capacity Forecast Details" width="100%" height="100%"
maximize="this.currentState='fullBldg'" restore="this.currentState=''"/>
<mx:HBox id="bottomCharts" width="100%" height="100%">
<v:SiteEVP id="evpDetails" width="100%" height="100%" title="Current Seat Demand by EVP"
maximize="this.currentState='fullEVP'" restore="this.currentState=''"/>
<v:BuildingType id="bldgType" width="100%" height="100%" title="Intended Capacity by Building Type"
maximize="this.currentState='fullBldgType'" restore="this.currentState=''"/>
<v:Building id="bldg" width="100%" height="100%" title="Current Utilization by Building"
maximize="this.currentState='fullBldgUtilization'" restore="this.currentState=''"/>
</mx:HBox>
</mx:VBox>
</mx:ViewStack>
</mx:VBox>
</mx:HBox>
</mx:VBox>
</mx:ViewStack>
</mx:WindowedApplication>
--
-- OK THIS IS MY CONTAINER FILE CALLED
-- BuildingDetails.mxml
--
<?xml version="1.0" encoding="utf-8"?>
<v:MaxRestorePanel xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:v="views.*"
layout="vertical">
<mx:Script>
<![CDATA[
import mx.collections.ICollectionView;
[Bindable]
public var dp:ICollectionView = null;
// import mx.collections.ArrayCollection;
// import mx.collections.GroupingField;
// import mx.collections.Grouping;
// import mx.collections.GroupingCollection;
// Callback function that hightlights in red less than 0
public function myColStyleFunc0(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["PREV_YR_ACTUAL"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc1(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_1"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc2(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_2"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc3(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_3"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc4(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_4"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc5(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_5"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc6(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_6"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc7(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_7"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc8(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_8"] < 0)
return {color:0xFF0000};
return null;
}
public function myColStyleFunc9(data:Object,
col:AdvancedDataGridColumn):Object
{
if(data["CUR_YR_9"] < 0)
return {color:0xFF0000};
return null;
}
]]>
</mx:Script>
<mx:NumberFormatter id="nf" useThousandsSeparator="true"/>
<mx:AdvancedDataGrid creationComplete="myGroup.refresh()" width="100%" height="100%">
<mx:dataProvider>
<mx:GroupingCollection id="myGroup" source="{dp}">
<mx:Grouping>
<mx:GroupingField name="BL_TYPE">
<mx:summaries>
<mx:SummaryRow summaryPlacement="group">
<mx:fields>
<mx:SummaryField dataField="PREV_YR_ACTUAL" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_1" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_2" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_3" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_4" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_5" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_6" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_7" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_8" operation="SUM" />
<mx:SummaryField dataField="CUR_YR_9" operation="SUM" />
</mx:fields>
</mx:SummaryRow>
</mx:summaries>
</mx:GroupingField>
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn dataField="BL_ID" width="200" headerText="Bldg" editable="false"/>
<mx:AdvancedDataGridColumn dataField="SUB_TYPE" headerText="Type" width="100" editable="false"/>
<mx:AdvancedDataGridColumn dataField="PREV_YR_ACTUAL" headerText="2008" width="100" textAlign="right" editable="false" formatter="{nf}" styleFunction="myColStyleFunc0" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_1" headerText="2009" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc1" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_2" headerText="2010" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc2" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_3" headerText="2011" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc3" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_4" headerText="2012" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc4" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_5" headerText="2013" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc5" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_6" headerText="2014" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc6" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_7" headerText="2015" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc7" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_8" headerText="2016" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc8" />
<mx:AdvancedDataGridColumn dataField="CUR_YR_9" headerText="2017" textAlign="right" width="100" editable="false" formatter="{nf}" styleFunction="myColStyleFunc9" />
</mx:columns>
</mx:AdvancedDataGrid>
<mx:ControlBar id="controls">
<mx:Button label="Pull Bldg Details" click="myGroup.refresh()"/>
</mx:ControlBar>
</v:MaxRestorePanel>