Nested properties and DataGridColumn
Posted by cornel | Filed under Flex
Almost every project that I have been involved with shares the same problem: by default, the DataGrid component cannot render by default nested properties – it can display only the top level property. For example : if you have the object Product with the properties name and company (and company has other properties) you can have a column displaying “name” but you cannot have one displaying “company.name”. The classic way to solve this is to declare a function which knows how to extract the data and specify the labelFunction property for the grid column. Personally I dislike that approach – I can have almost one hundred grids in my application - I would like to write dataField=“company.name” in a column definition and that’s all.
I have found several solutions based on extending DataGridColumn or by creating a custom item renderer but these solutions are not aware of ItemPendingException – and when you use LCDS you can have a lot of managed associations with lazy=”true”. So I’ve decided to write a custom grid column which knows how to deal with that condition. Below is the code and a small sample that shows how to use it. Currently, the component knows only to work with nested data – maybe later I will extend it to also work with indexed properties.
By the way there is also an enhancement request on JIRA to make the DataGrid support nested data by default.
1: public class DataGridColumnNested extends DataGridColumn{
2:
3: override public function itemToLabel(data:Object):String{
4: var currentData:Object = data;
5: if (data==null)
6: return “”;
7: if (dataField.indexOf(“.”) != -1){
8:
9: var fields:Array = dataField.split(“.”);
10:
11: try{
12: for each(var field:String in fields){
13: currentData = currentData[field];
14: if (currentData==null)
15: break;
16: }
17: }catch(ipe:ItemPendingError){
18: ipe.addResponder(new ItemResponder(
19: function (result:Object, token:Object=null){
20: itemToLabel(result.body);
21: },
22: function (fault:Object, token:Object=null){
23: trace(‘Error while loading’);
24: }
25: ));
26: }
27: }
28:
29: return super.itemToLabel(currentData);
30: }
31:
32: }
Usage:
1: <mx:DataGrid id=“companyGrid” width=“800″ dataProvider=“{productArray}” editable=“true”>
2: <mx:columns>
3: <mx:DataGridColumn dataField=“id” headerText=“Id” editable=“false”/>
4: <mx:DataGridColumn dataField=“name” headerText=“Product”/>
5: <c:DataGridColumnNested editable=“false” headerText=“Company name” dataField=“company.name”/>
6: </mx:columns>
7: </mx:DataGrid>
August 7th, 2008 at 2:06 am
Very cool…
To overcome this I’ve always just set a getter function on the data object.
public function get companyName() {return company.name;}
This could be a pain if you have lots to nested objects
August 8th, 2008 at 5:25 pm
Cornel, great post.
This solution is very helpfull.
I have another problem related with this.
The user needs to write the code of the company in the cell, and i want to assign this data to the code property of the company object.
Is this possible?
Thanks and sorry for my english.
Fabio
August 8th, 2008 at 10:34 pm
mc,
Yes, you will have to write lots of functions - and by the way if you are using LCDS with lazy managed associations you will have to take care of that in the functions. “product.company.name” will throw ItemPendingException if the Destination company has lazy set to “true”
August 8th, 2008 at 10:39 pm
Fabio,
Good question, I never had to that - My preference is to use grids for data visualisation and popups to edit the rows. I will study the next week this problem.
Don’t worry about the language, I’m not a native speaker myself
August 21st, 2008 at 3:10 am
I like your solution but am getting the following errors:
Severity and Description Path Resource Location Creation Time Id
1046: Type was not found or was not a compile-time constant: ItemPendingError. justFocused/src DataGridColumnNested.as line 21 1219280733452 25
1180: Call to a possibly undefined method ItemResponder. justFocused/src DataGridColumnNested.as line 22 1219280733452 26
I’m new to Flex and am probably missing something simple. Can you point me in the right direction? Thanks
August 21st, 2008 at 7:34 am
Hi Jeff,
Add the following import statements (before class definition):
import mx.controls.dataGridClasses.DataGridColumn;
import mx.collections.*;
import mx.collections.errors.ItemPendingError;
Let me know if it works.
August 22nd, 2008 at 1:41 am
Thanks for the quick and accurate reply - it works perfectly! Now do I have to have a custom sort? I created one using sortCompareFunction but get the following error: Find criteria must contain at least one sort field value. I read somewhere that I have to intercept the header messages and do my sort based on that — true? Suggestions?
And again, thanks for all your effort — greatly appreciated!
October 14th, 2008 at 11:07 pm
I recently extended the DataGrid to allow for nested properties because making a custom sort function and a custom label function can get quite tedious for every DataGrid you use with nested object properties. I allow for a DataGridColumn to use dataField=”object1.object2.object3.property” or dataField=”object1.objectList1[0].object2.objectList2[5].property” for example. Feel free to check it out on my blog.