I know it has been awhile since part one, but here is part two of Creating Custom Components and Item Renderers with Flex 2.
Item renderers are a tricky subject. They are like custom components, but are far more involved. They live inside components that are children of the List class (i.e. DataGrid, List, Horizontal List, Tile List). The best way to think of them is that for every row in your List there will be an instance of that item renderer in that list.
Here is a list of important things to note about the item renderer:
- Access to parent objects is dependent on how you implemented the Item renderer
- It’s very hard to access the item renderer from outer code, the parent application or the parent document.
- It is easy to access outer code from the item renderer
- Any code the item renderer wants to access must be public type
- If you create your item renderer in its own file you access the parent with parentDocument.publicVar
- If you create your item renderer in line you access the parent with outerDocument.publicVar
- Calling parentApplication.publicVar will give the item renderer access to anything at the Application level and lower (any components declared between the application tags)
I know all this seems confusing now, so lets jump into some quick examples to help you better understand how all this communication flows and to familiarize yourself with the two ways to create item renderers.
The following tutorial will show you how to create a simple item renderer using a custom component. I will not be going over inline item renderers. Inline item renderers tend to be messy and are far too confusing to create a good tutorial with. I do not use them if they can be at all avoided in real world applications.
First lets create a new project called ItemTest as you usually would. Once that is complete open ItemTest.mxml and add a DataGrid by dragging it onto the screen. This is where we will display our Item Renderer. Give the DataGrid an id of dgItemData, a width of 600 and height of 400. Switch to source view, your code should look like this:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:DataGrid x="10" y="10" id="dgItemData" height="400" width="600">
<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:Application>
At this point we want to get some data for our datagrid. Right-Click on your project and select New->File. Give the file a name of sampleData.xml. Copy the text below and paste it into sampleData.xml:
<root>
<Song>
<Artist>Taproot</Artist>
<Title>Again and Again</Title>
<Album>Gift</Album>
</Song>
<Song>
<Artist>Gorillaz</Artist>
<Title>Last Living Souls</Title>
<Album>Demon Days</Album>
</Song>
<Song>
<Artist>All That Remains</Artist>
<Title>Whispers (I Hear You)</Title>
<Album>The Fall of Ideals</Album>
</Song>
</root>
Now we need to connect the DataGrid to the sampleData.xml. I won’t go too far into this part, as there will be a tutorial on these later, but copy and paste the HTTPService below into ItemTest.mxml:
<mx:HTTPService id="srvData" url="./sampleData.xml" resultFormat="e4x" method="GET" useProxy="false" result="dgItemData.dataProvider = XML(srvData.lastResult).Song;"/>
ItemTest.mxml should now look like this in the source view:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:HTTPService id="srvData" url="./sampleData.xml" resultFormat="e4x" method="GET" useProxy="false" result="dgItemData.dataProvider = XML(srvData.lastResult).Song;"/>
<mx:DataGrid x="10" y="10" id="dgItemData" height="400" width="600">
<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:Application>
The code above will send out an HTTP GET request over port 80 for the file sampleData.xml. As I set the url to ./sampleData.xml it will automatically fill in the rest of the url to be whatever domain the application is running from. Its result will be in the e4x format (xml), and upon the result event it will assign our datagrid’s dataprovider with its data. The data will read, for every Song element in the root of the result creates a row in the datagrid.
Now let’s create the Item Renderer. Right-click on the created project, go to new, and create a new MXML component. Give it a filename of MyItem, base it on VBox, give it a width of 400 and a height of 100.
Now switch over to design view of your component. You should see a blank, white rectangle 400 pixels wide and 100 high. Lets add some content to our item renderer. Two Text components and a button should do the trick. Drag and drop two text components and a button from the Components List onto the VBox in that order. Give the top text an id of txtCom1 and the bottom text an id of txtCom2. Give the button an id of btnInfo and a label that says ‘Click Me’. If you view your source code it should look like this:
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="100">
<mx:Text text="Text" id="txtCom1"/>
<mx:Text text="Text" id="txtCom2"/>
<mx:Button label="Click Me" id="btnInfo"/>
</mx:VBox>
For aesthetics let’s center them in the VBox. Go to Design view and select the VBox of your item renderer and set its Horizontal Align to center.

Save your changes and now we can begin to link these components together. First we will need to create some ActionScript functions to call the data. Insert the following into your ItemTest.mxml file in between the Application tags:
<mx:Script>
<![CDATA[
import mx.controls.Alert;
//Run on the creationComplete event of the application
private function init():void
{
srvData.send();
}
//Called by the itemRenderer button when it is clicked
public function itemClick(title:String, artist:String, album:String):void
{
Alert.show(title + " - " + artist + " - " + album, "Song Info", Alert.OK, this);
}
]]>
</mx:Script>
Add the init(); function to the Application creationComplete event. To do this add the following line to the Application tag:
creationComplete="init();"
Your code for the ItemTest.mxml file should look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
//Run on the creationComplete event of the application
private function init():void
{
srvData.send();
}
//Called by the itemRenderer button when it is clicked
public function itemClick(title:String, artist:String, album:String):void
{
Alert.show(title + " - " + artist + " - " + album, "Song Info", Alert.OK, this);
}
]]>
</mx:Script>
<mx:HTTPService id="srvData" url="./sampleData.xml" resultFormat="e4x" method="GET" useProxy="false" result="dgItemData.dataProvider = XML(srvData.lastResult).Song;"/>
<mx:DataGrid x="10" y="10" id="dgItemData" height="400" width="600">
<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:Application>
Go back to your item renderer, MyItem.mxml and switch to source view. From here we need to set btnInfo to call the function we just created, itemClick, in the parent application. Add the following to the button’s tag:
click="parentApplication.itemClick(data.Title, data.Artist, data.Album);"
We also need to set the text. Add the following text values to your two text components:
text="{data.Title}"
text="{data.Artist}"
Your code in MyItem should now look like this:
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="100">
<mx:Text text="Text" id="txtCom1" text="{data.Title}"/>
<mx:Text text="Text" id="txtCom2" text="{data.Artist}"/>
<mx:Button label="Button" id="btnInfo" click="parentApplication.itemClick(data.Title, data.Artist, data.Album);"/>
</mx:VBox>
What the above code just did was say that for every item renderer created there will be a button called btnInfo created. When clicked, this button will send the following data to the public function itemClick in the parent application. The variable data holds all information contained in the row that the item renderer is in.
Switch back to ItemTest.mxml source view.
Now we need to set the item renderer. In the first DataGrid column, Column 1, remove the datafield, it is not needed when setting an item renderer. Modify it to look like the following instead:
<mx:DataGridColumn itemRenderer="MyItem" headerText="Column 1" width="400"/>
What this means is that for every row in this column display an instance of the Component MyItem. Also at this point give Column 1 a width of 400. Set the datafield for Column 2 to Album and Column 3 to Artist. Your datagrid should now look like this:
<mx:DataGrid x="10" y="10" id="dgItemData" height="400" width="600">
<mx:columns>
<mx:DataGridColumn itemRenderer="MyItem" headerText="Column 1" width="400"/>
<mx:DataGridColumn headerText="Column 2" dataField="Album"/>
<mx:DataGridColumn headerText="Column 3" dataField="Artist"/>
</mx:columns>
</mx:DataGrid>
Give the code a run. You should now see this in your main screen:

Still confused on item renderers? Don’t worry, they are by far the toughest concept to grasp when starting out with Flex and Actionscript. It took me a few tries creating them before I finally understood how they worked.
In my opinion the best way to think of them is this. Assume you have set the item renderer of a column in a datagrid. Your datagrid’s data provider contains 10 rows of information that would normally be displayed without an item renderer. Once you add the item renderer, there will still be 10 rows of information, only in the column with the item renderer you will see 10 distinct instances of your item renderer. Each item renderer instance in the 10 rows has a data variable which holds all data of that row. To explain the data variable lets look above real quick. The first item renderer in the first row of the datagrid dgItemData is a unique instance of the component MyItem and has a data variable. The data variable has access to the following information based on the sampleData.xml file which is the provider for the datagrid dgItemData:
<Song>
<Artist>Taproot</Artist>
<Title>Again and Again</Title>
<Album>Gift</Album>
</Song>
So by saying data.Artist we are really saying ‘Taproot’.
That is it for the Custom Components and Item Renderers tutorials. I am going to try and get these tutorials out on a more timely basis, probably one every week or two. I already know that the next tutorial will be on HTTPServices, XML, and using both to create a simple RSS Reader. As always, please feel free to comment what you think of the tutorial, anywhere I stated something wrong, or any helpful tips you may have for others.
Erich out.