It often happens that the data which needs to be viewed/presented in a Flex DataGrid comes from an XML file or JSON with more than one level of nesting. Unfortunately, by default, the Flex DataGrid allows you to display only single level nested object arrays.
This tutorial shows how you can extend the Flex DataGrid class to accomodate more complicated data structures. It will also show you how to make all the columns sortable, even when using nested data structures.
Introduction
This tutorial assumes that you know the basics of Flex, how to use Flex Builder, and how to write MXML files. You should have a copy of Flex Builder installed on your system.
Step 1: Setup the Flex Project
The first step is to setup the project in Flex Builder. Create a new project in Flex Builder with Project Name as “NestedDataGrid” and Application Type as “Web application (runs in Flash Player)”. Leave all other options at their default values and click Finish.

Step 2: Import Sample Data
The data that we’re going to show in the DataGrid is obtained from an XML file. Create a folder in your ‘src’ folder called ‘assets’ and put the data shown below in a file called ‘meetings.xml’. Alternatively, you can download the XML file from here and put it in the ‘assets’ folder.
<?xml version="1.0" encoding="UTF-8"?>
<meetings>
<meeting>
<priority>high</priority>
<presenter>
<name>Lisa Green</name>
<email>jdoe@company.com</email>
<phone>+330-7593</phone>
</presenter>
<date>12th July 2009</date>
<time>6:00 pm</time>
<place>Room 405</place>
</meeting>
<meeting>
<priority>medium</priority>
<presenter>
<name>Christopher Martin</name>
<email>cmartin@company.com</email>
<phone>+330-7553</phone>
</presenter>
<date>14th July 2009</date>
<time>11:00 am</time>
<place>Room 405</place>
</meeting>
<meeting>
<priority>high</priority>
<presenter>
<name>George Rodriguez</name>
<email>grodriguez@company.com</email>
<phone>+330-7502</phone>
</presenter>
<date>18th July 2009</date>
<time>10:00 am</time>
<place>Room 771</place>
</meeting>
<meeting>
<priority>high</priority>
<presenter>
<name>Jennifer Parker</name>
<email>jparker@company.com</email>
<phone>+330-5380</phone>
</presenter>
<date>20th August 2009</date>
<time>2:00 pm</time>
<place>Room 562</place>
</meeting>
</meetings>
Step 3: Make the Interface
Here’s a quick breakdown of building the interface to display the data and the appropriate ID values required for the code in this tutorial:
- Open the NestedDataGrid.mxml file, and go to the design view
- Drag and drop a ‘Panel’ from the Components view. Set its ID to “meetingsPanel” and Title to “Meetings”
- Set the height and width of the Panel to 500 and set the X and Y values to 0
- Drag and drop a ‘DataGrid’ onto the panel
- Set the X and Y values to 10
- Set the width to {meetingsPanel.width-40} and height to 45%
- Go to the source view, and in the ‘mx:Appication’ tag, add the attribute layout=”vertical”
Your interface should look similar to that shown in the image below:

The MXML in the source view should look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Panel x="0" y="0" width="500" height="500" layout="absolute" id="meetingsPanel" title="Meetings">
<mx:DataGrid x="10" y="10" width="{meetingsPanel.width-40}" height="45%">
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
Reading in the XML File
In the next three steps, we create an HTTPService component, read the data from the XML file and store it in a local variable. This is done in three stages:
Step 4: Create the HTTPService Component
Switch to the Source view of the MXML file and add the following code right below the mx:Application tag:
<mx:HTTPService id="readXML"
url="assets/meetings.xml" resultFormat="object"
result="httpResultHandler(event)" fault="httpFaultHandler(event)" />
The httpResultHandler() function will be called when the data has been fetched. If there’s an error in fetching the data, the httpFaultHandler() function is called. Note that this only creates the HTTPService object, the data has to be fetched by an explicit function call (See sub-step 3)
Step 5: httpResultHandler() and httpFaultHandler()
Add an mx:Script tag just below the mx:Application tag. Inside that, define the variable that will hold the incoming data and the functions to handle the events from the HTTPService component. The code to do that looks like this:
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
public var dataForGrid:ArrayCollection;
private function httpResultHandler(event:ResultEvent):void{
dataForGrid = event.result.meetings.meeting;
}
private function httpFaultHandler(event:FaultEvent):void{
Alert.show("Error occurred in getting string");
}
The variable ‘dataForGrid’ holds the data that we are going to read in. The ‘[Bindable]‘ tag makes sure that whenever the data changes (when it is read in), the DataGrid is updated accordingly. The XML is read in as an object which is passed throught the ‘ResultEvent’ event, and ‘event.result.meetings.meeting’ accesses the ArrayCollection of ‘meeting’ objects.
Step 6: Get the Data From the XML File
In this step, the actual function call to get the XML data is done. An intialize function is assigned to the event that is triggered everytime the application loads – the ‘creationComplete’ event. Add the attribute creationComplete=”getData()” to the ‘mx:Application’ tag and define the function ‘getData()’ as below (to be added after the ‘httpFaultHandler’ function):
private function getData():void{
readXML.send();
}
This makes the HTTPService object get the data from the file. Once the data is retrieved, the ‘result’ event is triggered which calls the ‘httpResultHandler()’ function. If there’s a problem getting the data, the ‘fault’ event is triggered, which calls the httpFaultHandler() function.
Step 7: Milestone
At this point your NestedDataGrid.mxml should look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="getData()">
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
public var dataForGrid:ArrayCollection;
private function httpResultHandler(event:ResultEvent):void{
dataForGrid = new ArrayCollection(event.result.meetings.meeting);
}
private function httpFaultHandler(event:FaultEvent):void{
Alert.show("Error occurred in getting string");
}
private function getData():void{
readXML.send();
}
]]>
</mx:Script>
<mx:HTTPService id="readXML"
url="assets/meetings.xml" resultFormat="object"
result="httpResultHandler(event)" fault="httpFaultHandler(event)" />
<mx:Panel width="500" height="500" layout="vertical" id="meetingsPanel" title="Meetings">
<mx:DataGrid width="{meetingsPanel.width-40}" height="45%">
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
Step 8: DataGrid with Non-Nested Data
I’ll just briefly point out why nested data poses problems in display, by first demonstrating how you show non-nested data. Say, from the XML file above, you only wanted to show the date, place and priority of the meetings (and not the presenter information). The below code will be able to display it without any problems (contents of ‘mx:Panel’ shown here. All other code is the same):
<mx:DataGrid width="{meetingsPanel.width-40}" height="45%" dataProvider="{dataForGrid}">
<mx:columns>
<mx:DataGridColumn headerText="Priority" dataField="priority"/>
<mx:DataGridColumn headerText="Date" dataField="date"/>
<mx:DataGridColumn headerText="Time" dataField="time"/>
<mx:DataGridColumn headerText="Place" dataField="place"/>
</mx:columns>
</mx:DataGrid>
The result of the this would be the following application:
Note that the dataProvider attribute of the DataGrid can be directly assigned to the the ArrayCollection ‘dataForGrid’, and each DataGridColumn inside is given a dataField attribute that directly corresponds to the property name. However, suppose you want to access the presenter’s name information, it can be accessed as “presenter.name”. If you try giving this value to the ‘dataField’ you’ll get an error. This is because, Flex doesn’t support nested objects by default. Read on to learn how to solve this problem by extending the DataGridColumn class and writing your own code to handle this case.
Step 9: Creating the NestedDataGridColumn Class
We redefine some functions in the DataGrid column class to circumvent the problem outlined above. First create a folder in the ‘src’ directory called ‘classes’. Create a new ‘ActionScript Class’ in that folder, named “NestedDataGridColumn”. In the ‘Superclass’ field, click ‘Browse…’ and select ‘DataGridColumn’ from the list that pops up. Leave everything else at the default values, and click ‘Finish’. A new file should have been created and populated with the following code:
package classes
{
import mx.controls.dataGridClasses.DataGridColumn;
public class NestedDataGridColumn extends DataGridColumn
{
public function NestedDataGridColumn(columnName:String=null)
{
super(columnName);
}
}
}
Step 10: Declaring the ‘nestedDataField’ Property
In the NestedDataGridColumn class, add a public bindable variable called ‘nestedDataField’. We’ll use this instead of the default ‘dataField’ property to pass the field name. This is vital, because if the default ‘dataField’ property is used, an error saying Error: Find criteria must contain at least one sort field value. will occur when we try to sort the DataGrid after having defined the custom sort function later on.
Step 11: Redefining the ‘itemToLabel’ Funtion
As you can see, the new class we created has already been populated with a constructor. Leave the constructor as it is and below that add the following function:
override public function itemToLabel(data:Object):String
{
var fields:Array;
var label:String;
var dataFieldSplit:String = nestedDataField;
var currentData:Object = data;
//check if the nestedDataField value contains a '.' (i.e. is accessing a nested value)
if(nestedDataField.indexOf(".") != -1)
{
//get all the fields that need to be accessed
fields = dataFieldSplit.split(".");
for each(var f:String in fields)
//loop through the fields one by one and get the final value, going one field deep every iteration
currentData = currentData[f];
if(currentData is String)
//return the final value
return String(currentData);
}
//if there is no nesting involved
else
{
if(dataFieldSplit != "")
currentData = currentData[dataFieldSplit];
}
//if our method hasn't worked as expected, resort to calling the default function
try
{
label = currentData.toString();
}
catch(e:Error)
{
label = super.itemToLabel(data);
}
//return the result
return label;
}
Redefining the ‘itemToLabel’ function is the key to being able to access nested data in your DataGrid. The itemToLabel function controls what is shown in the DataGrid rows. So we use it here to ask Flex to show the nested data in the manner that we have specified.
As you can see, the function definition starts with the ‘override’ keyword, which means the default pre-defined function of the same name is being overridden in favour of the function you have defined. Each statement is explained in the comments. In brief, what the function does is check if nested data fields is being accessed (if a ‘.’ is present). If it is, get each data field name, and iterate through the dataProvider, going deeper each step by accessing the child field.
The ‘itemToLabel’ function is called by Flex with an argument which contains the ArrayCollection that was specified as the dataProvider to the dataGrid. All attributes of the NestedDataGridColumn (when it is used in the mxml file) are directly accessible, and any public properties defined in this class can be assigned a value in the MXML. In our NestedDataGrid.mxml file, we replace the ‘mx:DataGridColumn’ components with ‘classes:NestedDataGridColumn’ component, and assign the specific elements that we want to show in the columns to the ‘nestedDataField’ attribute (which was declared in the ‘NestedDataGridColumn.as’ file). The DataGridColumn now should look like this:
<mx:DataGrid x="10" y="10" width="{meetingsPanel.width-40}" height="45%" dataProvider="{dataForGrid}">
<mx:columns>
<classes:NestedDataGridColumn headerText="Priority" nestedDataField="priority" width="60"/>
<classes:NestedDataGridColumn headerText="Presenter Name" nestedDataField="presenter.name" sortable="false"/>
<classes:NestedDataGridColumn headerText="Presenter Phone" nestedDataField="presenter.phone" width="90" sortable="false"/>
<classes:NestedDataGridColumn headerText="Date" nestedDataField="date" width="110"/>
<classes:NestedDataGridColumn headerText="Time" nestedDataField="time" width="70"/>
<classes:NestedDataGridColumn headerText="Place" nestedDataField="place" width="70"/>
</mx:columns>
</mx:DataGrid>
Note that I’m directly specifying the ‘nestedDataField’ property as the “presenter.name” and “presenter.phone” here. Also, I’ve added widths to the columns and set the width of the ‘mx:Panel’ component to 600px for better display. I’ve added the ‘sortable’ property to be false to the two new columns. If you remove this (or set it to true) and run the program the column won’t sort. We’ll solve this in the next step by defining our own sort function. For now the application should look like this:
Step 12: Writing the Custom Sort Function
The only thing left now is to define the custom sorting function so that sorting will also be enabled in all the fields (say, you want to sort the presenter names alphabetically). Add the function called ‘mySortCompareFunction’ below the ‘itemToLabel’ function as given:
private function mySortCompareFunction(obj1:Object, obj2:Object):int{
var fields:Array;
var dataFieldSplit:String = nestedDataField;
var currentData1:Object = obj1;
var currentData2:Object = obj2;
if(nestedDataField.indexOf(".") != -1)
{
fields = dataFieldSplit.split(".");
for each(var f:String in fields){
currentData1 = currentData1[f];
currentData2 = currentData2[f];
}
}
else
{
if(dataFieldSplit != ""){
currentData1 = currentData1[dataFieldSplit];
currentData2 = currentData2[dataFieldSplit];
}
}
if(currentData1 is int && currentData2 is int){
var int1:int = int(currentData1);
var int2:int = int(currentData2);
var result:int = (int1>int2)?-1:1;
return result;
}
if(currentData1 is String && currentData2 is String){
currentData1 = String(currentData1);
currentData2 = String(currentData2);
return (currentData1>currentData2)?-1:1;
}
if(currentData1 is Date && currentData2 is Date){
var date1:Date = currentData1 as Date;
var date2:Date = currentData2 as Date;
var date1Timestamp:Number = currentData1.getTime();
var date2Timestamp:Number = currentData2.getTime();
return (date1Timestamp>date2Timestamp)?-1:1;
}
return 0;
}
This function will be called by Flex with two objects, and it’s expected to return either -1.0 or 1 depending on whether the first object is greater than, equal to, or less than, respectively, the second object. Flex takes care of the actual sorting.
This function uses the same logic as the ‘itemToLabel’ function to get the appropriate nested value. Then depending upon the type of the value (whether it be int, String, or Date) it compares it appropriately, and returns -1 if ‘currentData1′ is greater than ‘currentData2′, 0 if they are equal, and 1 if ‘currentData2′ is greater than ‘currentData1′.
Step 13: Hooking up the Custom Sort Function
If you noticed, ‘customSortCompareFunction’ is not a predefined function in the class DataGridColumn which we override. This function has to be assigned as the sorting function in a different way. We have to assign to the pre-defined variable ‘sortCompareFunction’ the name of the sorting function, which is ‘customSortCompareFunction’ in our case. This should be done inside the constructor. The constructor now looks like this:
public function NestedDataGridColumn(columnName:String=null)
{
//the custom sort function being assigned to the pre-defined variable
sortCompareFunction = mySortCompareFunction;
super(columnName);
}
Once this is done, you’re all set. You now have a custom class that can handle arbitrarily nested data to show in a DataGrid. And you can sort the grid as you want.
Conclusion
Today you learnt how to circumvent a limitation of the FlexDataGrid class to get arbitrarily nested data, and show it in a DataGrid. You also learned how to define your own sorting function so that the grid remains sortable. You can now use this NestedDataGridColumn in all your applications without any overhead.
You can further extend the ‘itemToLabel’ function to include other arbitrary format of access – say, accessing arrays inside the child objects, or accessing xml attributes. You can also further extend the sort function to sort other types of data. You might also be able to add other features like colouring the rows based on the meeting priority and showing more details about the presenter by clicking a row.
Thanks for reading :)




Great tutorial!!!
Thank you.
Nice application, I will try to use flex, I like more flash but it seems powerful program.
Flex fits in better when making applications and the like. I started working on Flex when making an Adobe AIR application. For AIR, Flex makes lots of things really simple.
This is my personal step into Flex! Thank you it looks really easy to understand ;)
You’re welcome. Hope you get much deeper into Flex. It’s quite a powerful and interesting platform.
Well I have tried Flex but can’t use it yet, hope your tuts will help.
Extremely useful thanks!
You’re welcome.
Interesting article. Do post more!
Thanks :)
Hmmm, seems very similar to http://buildinternet.com/2009/01/flex-3-basics-data-grids-with-xml/
See the demo here – http://buildinternet.com/live/datagrids/dataGrids.html
And your sort order is back to front.
It is only similar as far as the result is concerned. You see, the link you show doesn’t display nested xml data. The nested part is the whole point of this tutorial.
My browser crashes when trying to sort dates or values. Has this happen to anybody else?
Good tut though
Yeah I guess that column should be made non-sortable. Thanks for pointing it out.
Javier is right here.
Though the example (as in last milestone) is not supposed to sort the data, still if I Click the headers in the dataGrid, the browser crashes.
You might want to make the columns “non-sortable”.
Nice tutorial still.
Great article!!
Sometimes people get lost on these types of data. Your tutorial is a great solution for those who want to learn a little more about overrideing default flex framework classes.
Another more simple solution it’s to simply add a item render on another cell and attribute to him the nested value, something like this should work fine:
simply add 2 more collumns on your “default” datagrid, and for each one add a label item render to it, like this:
This will work to. About the sort function, the supports the sortCompareFunction where you cand add a sort function, like this:
import mx.utils.ObjectUtil;
private function sortFieldValues(ita:Object, itb:Object):int {
var value1:String = ita.presenter.name
var value2:String = itb.presenter.name
return ObjectUtil.stringCompare(value1, value2);
}
About the phone number, the process is the same! Your job is great but maybe a little complex for begginers. This is only one more simple solution to do the same job.
Cheers!
Yeah that is one solution, but it is too specific. I have shown here a general method which doesn’t involve writing an itemrenderer each time.
Also, I guess I should have mentioned in the introduction, but this tutorial is for intermediate level Flex programming, not beginners. So hopefully, it doesn’t intimidate those who come here to learn flex ;)
Hi Mario,
I am looking for a solution to the exact problem as in this article.
Can you please post the code sample for the alternate that you suggested for the nested data grids.
oops I found it ! sory about that …Good Job Though both Anand and Mario!
Humm.. the item render code was not presented, the full code be read here: http://viewer.zoho.com/docs/gPavJ
Hey an error creeps up:::
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at classes::NestedDataGridColumn/itemToLabel()[C:\Documents and Settings\beetle\My Documents\Flex Builder 3\Flex Project\NestedDataGrid\src\classes\NestedDataGridColumn.as:96]
at mx.controls.dataGridClasses::DataGridBase/makeListData()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\controls\dataGridClasses\DataGridBase.as:1311]
at mx.controls::DataGrid/http://www.adobe.com/2006/flex/mx/internal::setupRendererFromData()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\controls\DataGrid.as:1643]
at mx.controls::DataGrid/commitProperties()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\controls\DataGrid.as:1606]
at mx.core::UIComponent/validateProperties()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:5670]
at mx.managers::LayoutManager/validateProperties()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:519]
at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:639]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8460]
at mx.core::UIComponent/callLaterDispatcher()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8403]
Thanks…
I tried your example and it keeps failing in public function findItem in sort.as
on line if (fieldsForCompare.length == 0)
{
message = resourceManager.getString(
“collections”, “findRestriction”);
throw new SortError(message);
}
else
any idea’s?
for me putting dataField=”" in the constructor worked, so the sortFunction doesn receive any null objects… dont know if its a very good way though, but it seems to work
public function NestedDataGridColumn(columnName:String=null)
{
super(columnName)
sortCompareFunction = mySortCompareFunction
dataField = “”;
}
Thanks for making this article/tutorial… really informative and helpful.
This is great. I’m just learning Flex so this was good for me.
Awesome tutorial, however i have a slightly different nested data issue.
0
00
4V79
0000-00-00
http://www.tvrage.com/Buffy_The_Vampire_Slayer/episodes/329033
Unaired Pilot
1
01
4V01
1997-03-10
http://www.tvrage.com/Buffy_The_Vampire_Slayer/episodes/28077
Welcome to the Hellmouth (1)
http://images.tvrage.com/screencaps/15/2930/28077.png
I have an overall item title “Season” and multiple children below it. Is there any way of keeping “Season” column the same for each of the below episodes?
Great stuff !
Would it be possible that ‘a meeting’ has two or more ‘presenters’ ?
I tried to change the XML file so and then the whole data grid was empty. If I added multiple dates for a meeting that worked ok.
Looking for a solution for the same problem you mentioned!!!! Did you find one? If yes then please do share..
hi ,
very helpful post. my problem got solved of displaying nested property of object in datagrid. I have kept editable=”true” of datagrid so that user can edit data.
But on click event of submit button i can’t get edited data column of datagrid for which i have set datafield to nested object property. so is there any extra function need to override?
Thank and regards
hi,
Code for reading an xml data located in localhost
hi,
Code for reading an xml data located in localhost.
Thanks especially for the nested data grid column. Very good tutorial, kudos to you.
I am new to Flex and this tutorial was well explained .
Thanks !!!!!!
Hi,
I am getting a null object reference at itemToLabel function. Basically, I am getting data object as null.
Can you please help me out with this..Thanks
Hi, I think that this issue is now supported natively.
Looking to the DataGridColumn.as class in Flex 3.5, the nested data case seems to be handled.
Hello, I had a problem when I wanted to sort my datagrid with paging.
To fix this bug, I made the following changes in function mySortCompareFunction()
1. private function mySortCompareFunction(obj1:Object, obj2:Object):int{
2. var fields:Array;
3. var dataFieldSplit:String = nestedDataField;
4. var currentData1:Object = obj1;
5. var currentData2:Object = obj2;
6.
7. if(nestedDataField.indexOf(“.”) != -1)
8. {
9. fields = dataFieldSplit.split(“.”);
10.
11. for each(var f:String in fields){
12. currentData1 = currentData1[f];
13. currentData2 = currentData2[f];
14. }
15.
16. }
17. else
18. {
19. if(dataFieldSplit != “”){
20. currentData1 = currentData1[dataFieldSplit];
21. currentData2 = currentData2[dataFieldSplit];
22. }
23. }
24.
25.
44. return ObjectUtil.compare(currentData1,currentData2);;
45. }
In itemToLabel function (), I also added the following code to avoid having a nullpointer.
if (!data) return ” “;
Amazing! This definitely saved me!
Very helpful!! Thank you very much!
I’m new in Flex and this is awesome post for me!
I started to implement your suggestion and then found out that the flex 4.6 build already has this exact problem resolved in mx:DataGridColumn so there is no need to override the class.
View the DataGridColumn source set DataField to see.