Flex - Dynamic DataGrid when XML is unkown
This article is from the original REM DEV blog (2008–2010). Some of the technologies it covers (Flex, Flash, AIR, JavaFX 1.x) have since been retired.
This script comes in handy if you are dynamically building select statements, and then sending the results to Flex in xml format. The xml might look something like this...
<row>
<firstName>
Joe
</firstName>
<lastName>
Jackson
</lastName>
</row>
If you decide to adjust your query to something like this...
<row>
<firstName>
Joe
</firstName>
<middleName>
Arther
</middleName>
<lastName>
Jackson
</lastName>
</row>
you won't have to change anything in the ActionScript, it should be able to display the new field in a DataGrid automatically.
Here's the code...
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.*;
import flash.errors.*;
import mx.controls.*;
[Bindable] private var xmlList:XMLList = new XMLList();
private function init():void{
//load the xml file...
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, xmlLoadComplete);
xmlLoader.load(new URLRequest("xml/ElementReport.xml"));
}
private function xmlLoadComplete(evt:Event):void
{
try{
//get all the child elements of the root
xmlList = XML(evt.target.data).children();
//check to make sure there are results
if(xmlList.length() < 1){
Alert.show("There were no results that matched your search criteria");
return;
}
//create array that will become the columns array of the datagrid
var dgCols:Array = new Array();
//get each child element of the first item in xmlList and put them into an XMLList
//each child element will represent a column in the datagrid
var xmlColumns:XMLList = xmlList[0].children();
for(var x:uint=0; x < xmlColumns.length(); x++){
var xml:XML = xmlColumns[x];
//create a datagrid column for each xml element
var col:DataGridColumn = new DataGridColumn();
col.headerText = xml.name();
col.dataField = xml.name();
//if the text inside an xml element is decoded you can set the labelFunction
//see the function below...
col.labelFunction = scrubContent
dgCols.push(col);
}
dgReport.columns = dgCols;
dgReport.dataProvider = xmlList;
}catch(e:Error){
Alert.show(e.message);
}
}
private function scrubContent(item:Object, col:DataGridColumn):String{
var xml:XML = XML(item);
var df:String = col.dataField;
//you might have to decode the content first
//if it is content that was created by a RichTextEditor, you'll also
//have to run it through cleanHTML()
//found it at http://thanksmister.com/?tag=richtexteditor
return cleanHTML(decodeURI(xml.child(df)));
}
private function cleanHTML(str:String):String
{
var pattern:RegExp = /<TEXTFORMAT.*?>/g;
var str:String = str.replace(pattern, "");
pattern = /<FONT.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/FONT.*?>/g;
str = str.replace(pattern, "");
pattern = /<P.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/P.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/TEXTFORMAT.*?>/g;
str = str.replace(pattern, "");
return str;
}
]]>
</mx:Script>
<mx:VBox id="vbox">
<mx:DataGrid id="dgReport" width="600" />
</mx:VBox>
</mx:Canvas>
<row>
<firstName>
Joe
</firstName>
<lastName>
Jackson
</lastName>
</row>
If you decide to adjust your query to something like this...
<row>
<firstName>
Joe
</firstName>
<middleName>
Arther
</middleName>
<lastName>
Jackson
</lastName>
</row>
you won't have to change anything in the ActionScript, it should be able to display the new field in a DataGrid automatically.
Here's the code...
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.*;
import flash.errors.*;
import mx.controls.*;
[Bindable] private var xmlList:XMLList = new XMLList();
private function init():void{
//load the xml file...
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, xmlLoadComplete);
xmlLoader.load(new URLRequest("xml/ElementReport.xml"));
}
private function xmlLoadComplete(evt:Event):void
{
try{
//get all the child elements of the root
xmlList = XML(evt.target.data).children();
//check to make sure there are results
if(xmlList.length() < 1){
Alert.show("There were no results that matched your search criteria");
return;
}
//create array that will become the columns array of the datagrid
var dgCols:Array = new Array();
//get each child element of the first item in xmlList and put them into an XMLList
//each child element will represent a column in the datagrid
var xmlColumns:XMLList = xmlList[0].children();
for(var x:uint=0; x < xmlColumns.length(); x++){
var xml:XML = xmlColumns[x];
//create a datagrid column for each xml element
var col:DataGridColumn = new DataGridColumn();
col.headerText = xml.name();
col.dataField = xml.name();
//if the text inside an xml element is decoded you can set the labelFunction
//see the function below...
col.labelFunction = scrubContent
dgCols.push(col);
}
dgReport.columns = dgCols;
dgReport.dataProvider = xmlList;
}catch(e:Error){
Alert.show(e.message);
}
}
private function scrubContent(item:Object, col:DataGridColumn):String{
var xml:XML = XML(item);
var df:String = col.dataField;
//you might have to decode the content first
//if it is content that was created by a RichTextEditor, you'll also
//have to run it through cleanHTML()
//found it at http://thanksmister.com/?tag=richtexteditor
return cleanHTML(decodeURI(xml.child(df)));
}
private function cleanHTML(str:String):String
{
var pattern:RegExp = /<TEXTFORMAT.*?>/g;
var str:String = str.replace(pattern, "");
pattern = /<FONT.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/FONT.*?>/g;
str = str.replace(pattern, "");
pattern = /<P.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/P.*?>/g;
str = str.replace(pattern, "");
pattern = /<\/TEXTFORMAT.*?>/g;
str = str.replace(pattern, "");
return str;
}
]]>
</mx:Script>
<mx:VBox id="vbox">
<mx:DataGrid id="dgReport" width="600" />
</mx:VBox>
</mx:Canvas>