DataGrid, labelFunction and namespaces
In a previous post I talked about my preferred method in Flex 2 for dealing with XML data that contains namespaces. Another task that gets complicated by the presence of 'namespaced XML' is populating a DataGrid with that data. Despite the usefulness of the use namespace directive, I have been unable to populate a DataGrid just by using the dataField attribute, as can be done when your data does not contain namespaces.
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
</mx:columns>
</mx:DataGrid>
The method I employ uses the labelFunction attribute of DataGridColumn, something that is most commonly used to let you specify a function to handle the formatting of data you would like displayed in that column. This approach allows you to use a single function for both special formatting of data and to gain access to data that resides in a namespace. Here is the basic format of my labelFunction:
{
use namespace DOCUMENT_METADATA_NAMESPACE;
var q:QName = new QName(DOCUMENT_METADATA_NAMESPACE, obj_dataGridColumn.dataField);
var str_data:String = obj_data[q];
switch(obj_dataGridColumn.dataField)
{
case "Status":
return (str_data == "InProgress") ? "In Progress" : str_data;
break;
case "PlanDataDate":
return str_data.substr(0, str_data.indexOf(" "))
break;
default:
return str_data;
break;
}
}
Another item that has proven useful for dealing with namespaced XML is the QName class. Short for 'qualified name', the QName constructor allows you to specify a namespace and a local name, which it uses to address the data you are targeting. Once we establish our QName object, we use it to reference the desired property of the data object (obj_data) that is passed into our labelFunction. Also notice that the local name is determined by the dataField attribute of the DataGridColumn object that was passed into the function. We now have a variable (str_data) that should contain the data from the node in our XML that has the same name as specified by our dataField attribute.
As shown in the first two cases, you can do further formatting to this data if desired. The default case takes care of all non-special cases, for when you would like to display the data as it exists in the XML and were simply using the labelFunction to get around namespace issues. Finally, here is a simple example of a DataGrid that uses our genericLabelFunction.
<mx:columns>
<mx:DataGridColumn headerText="Industry" dataField="Industry" labelFunction="genericLabelFunction"/>
<mx:DataGridColumn headerText="Plan Date" dataField="PlanDataDate" labelFunction="genericLabelFunction"/>
<mx:DataGridColumn headerText="Status" dataField="Status" labelFunction="genericLabelFunction"/>
<mx:DataGridColumn headerText="Group Size" dataField="PlanSizeGroup" labelFunction="genericLabelFunction"/>
</mx:columns>
</mx:DataGrid>
You can leave a response, or trackback from your own site.

Man, I cannot /tell/ you how great it is to be able to find a solution at 12:30 AM for a problem that would figure rather prominently in what you’re showing to the executive team at 12:30 PM. Thanks a lot Ben, your contribution is greatly appreciated.
This is beautiful!! I have been looking for this for over a day and now will be able to display data from .Net (with namespaces) within my datagrid.
One question, though. When I attempt to modify data, Flex ignores the namespace thus creating a new node entry within the bound XML. The new entry has the same tag name as what I want updated without a namespace.
If I manually update my XML, I will have the correct value in the “namespaced” node _and_ in the “non-namespaced” node.
Any thoughts?
Hi Bruce, I’m glad this helped. I can’t say I have any ideas on what might be happening with your xml though. In most cases these days I have actually opted to leave resultFormat alone (defaults to object) so that Flex will create objects for me. I tend to only use e4x if I need to access a limited number of deeply nested properties since the .. operator makes it so easy. You can use the ObjectTranslator class from darronschall.com to convert the generic objects Flex will create into class instances.
HTH,
Ben
hi nice site.
Thanks a lot from Hungary (too)!
It was very usefull for me in my thesis!
The site is very good (with easy English, and useful examples)!
Szoke.
Would this mess up sorting? I added the function to my project in order for it to work, but now clicking on a column name does not sort properly. Good article, though. It helped me immensely.
Hi Nolan, glad it helped. What exactly is the problem you’re seeing? You may need a custom sort function.
Yep… I didn’t realize at first that I would need a custom sort function if I used a label function. I got it working though. Thanks!
Thanks, I searched a LONG time for this. You helped a lot. I will post my labelFunction, pretty basic, but works for what I needed, which was simply to remove the freakin’ namespace:
private function genericLabelFunction(dgcXML:Object,dcg:DataGridColumn):String
{
var currentItem:XML = XML(dgcXML);
var ns:Namespace = currentItem.namespace();
var displayValue:String = currentItem.ns::[dcg.dataField];
return displayValue;
}
Actually i am using httpservice and datagrid and i am generating xml from j2ee server that the httpservice will look on and i want some thing like this the xml should contain value and want attibute to be my column name in datagrid could u suggest me some thing
Hi,
Thanks for the post! Do you have the source file for this example somewhere?
Thanks!
Ben kicks ass!
another (possible) option here is to just remove the namespace from the XML.
the following code will not work out of context, but this is what i did to get my dataGrid/dataField to work right:
var xStr:String = incomingXML.toXMLString();
var rg:RegExp = /<v3:/g; // my namespace was ‘v3′
xStr = xStr.replace(rg,”<”); take out the v3 but leave the open bracket
rg = new RegExp(“</v3:”, “g”); // dont forget the closing tags
xStr = xStr.replace(rg,”</”); // again, you have to leave the bracket and close
incomingXML = XML(xStr); // make back your XML object.
this assumes that you dont need the namespace anywhere else in your code; i did not. and this worked like a charm with no hacks.
Thanks for the post Ben, forms an excellent support group for us silent Flex datagrid namespace sufferers.
Also, many thanks to Rick George. Your elegant solution works like a charm.
Thanks a Lot.
Okay the rendering of data in the grid works, but how do we go about constructing the XML with namespaces back – especially when you edit the cell in the datagrid.
I’m stuck here. Any thoughts?
Woot! Namespaces are being a PITA. Thanks for this.
Hi, I’ve updated the function to allow for multiple namespaces and attributes. I think it makes sense and it seems to work well, but I have not been at this very long.
private function genericLabelFunction(obj_data:Object, obj_dataGridColumn:DataGridColumn):String {
//all the namespaces in order of preference:
var qnames:Array = new Array();
qnames.push(new QName(atom, element));
qnames.push(new QName(gf, element));
//see if we have an attribute. If so, split
var split:Array = String(obj_dataGridColumn.dataField).split(“.”);
var element:String;
var attribute:String;
if (split.length > 1) {
element = split.slice(0, split.length – 1).join(“.”);
attribute = split[split.length - 1];
} else {
element = String(obj_dataGridColumn.dataField);
}
//find a namespace with something in it
var str_data:String;
for (var i:int = 0; i < qnames.length; i++) {
if (attribute != null) {
str_data = obj_data[qnames[i]][attribute];
} else {
str_data = obj_data[qnames[i]];
}
if (str_data != null && str_data != "") {
break;
}
}
//format various data in different ways
switch(obj_dataGridColumn.dataField) {
case "Status":
return (str_data == "InProgress") ? "In Progress" : str_data;
break;
case "PlanDataDate":
return str_data.substr(0, str_data.indexOf(" "))
break;
default:
return str_data;
break;
}
}
hopefully this won't get too mangled.
Apologies for spamming the place, but I rearranged the code and broke it prior to uploading it, here it is again.
private function genericLabelFunction(obj_data:Object, obj_dataGridColumn:DataGridColumn):String {
//see if we have an attribute. If so, split
var split:Array = String(obj_dataGridColumn.dataField).split(“.”);
var element:String;
var attribute:String;
if (split.length > 1) {
element = split.slice(0, split.length – 1).join(“.”);
attribute = split[split.length - 1];
} else {
element = String(obj_dataGridColumn.dataField);
}
//all the namespaces in order of preference:
//more can be pushed if needed (change atom and gf)
var qnames:Array = new Array();
qnames.push(new QName(atom, element));
qnames.push(new QName(gf, element));
//find a namespace with something in it
var str_data:String;
for (var i:int = 0; i < qnames.length; i++) {
if (attribute != null) {
str_data = obj_data[qnames[i]][attribute];
} else {
str_data = obj_data[qnames[i]];
}
if (str_data != null && str_data != "") {
break;
}
}
//format various data in different ways
switch(obj_dataGridColumn.dataField) {
case "Status":
return (str_data == "InProgress") ? "In Progress" : str_data;
break;
case "PlanDataDate":
return str_data.substr(0, str_data.indexOf(" "))
break;
default:
return str_data;
break;
}
}