One of the coolest and most useful features I use in Flex are item renderers. They allow us to customize how lists and datagrids display information. This tutorial is going to show how to use three different types of item renderers, drop-in, inline, and custom components. I actually used item renderers in an earlier tutorial on using Advanced Datagrid Topics to get song information. But this tutorial is going to go a bit more in depth on the topic.
Below is what we are going to build today. A simple datagrid which we display information about a couple songs and whether they are a favorite of ours. This example uses all three types of item renderers. It uses a drop-in for the checkbox, an inline for the picture and name, and finally a more complex custom item renderer for the rating. This only touches on the possibilities of what can be done though.
Starting with the user interface as usual we can setup a basic structure for our application. The initial setup is a simple application with a panel and a single datagrid component. The datagrid has three columns but only one has a specified datafield, the last one. Also at this point I added some data by manually creating an ArrayCollection inside the dataProvider property of the datagrid to just create some dummy song information. Each item inside the Array is a general object with a few properties set. So the start of our working code looks like:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="530" height="405">
<mx:Panel x="0" y="0" width="530" height="405" layout="absolute"
title="Item Renderers">
<mx:DataGrid x="0" y="0" width="510" height="365">
<mx:columns>
<mx:DataGridColumn headerText="Song"/>
<mx:DataGridColumn headerText="Rating" width="125"/>
<mx:DataGridColumn headerText="Favorite" dataField="isFavorite" width="75"/>
</mx:columns>
<mx:dataProvider>
<mx:ArrayCollection>
<mx:Array>
<mx:Object title="Stairway to Heaven" artist="Led Zepplin"
art="/files/led_zep.jpg" rating="4.5" isFavorite="true" />
<mx:Object title="How to Save a Life" artist="Fray"
art="/files/fray.jpg" rating="4" isFavorite="false" />
<mx:Object title="Sinnerman" artist="Nina Simone"
art="/files/nina_sim.jpg" rating="5" isFavorite="true" />
<mx:Object title="Take On Me" artist="Aha"
art="/files/aha.jpg" rating="3.5" isFavorite="false" />
</mx:Array>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
Drop-in Item Renderer
The first item renderer I am going to show is the drop-in. This is the simplest in form and execution, but is the most limited in functionality. We use this type for the check box to show if the song is a favorite of ours. The drop-in item renderers will take the data corresponding to the datafield and use it to define a property of the item renderer. Most of the time these are properties that defined the display of the component being used for the item renderer. Also there are only a certain number of components that can be used in this way, for a full list of these and the properties that can be used check out this livedocs page.
To get one of the drop-in renderers working all we need to do is simply
set a property on the DataGridColumn named itemRenderer. In the third
column we are going to set this property equal to
mx.controls.CheckBox, which is the name of the component we want to
use for the item renderer. Now we have a nice pretty checkbox instead of
"true" or "false". But if you remember I mentioned they were limited in
functionality, well this is very true because beyond what we have done
we can't really do much else. This includes not being able to disable
the checkbox, change the alignment, or anything else. The following code
is our new DataGridColumn for the favorite property.
<mx:DataGridColumn headerText="Favorite" dataField="isFavorite" width="75"
itemRenderer="mx.controls.CheckBox"/>
Inline Item Renderer
The next item renderer I am going to jump into is the inline item
renderer, which gives us a whole lot more functionality than the drop-in
and isn't much harder to implement. These are written as small
components added directly into the itemRenderer property of the
DataGridColumn. These let us use the current row data to display the
information however we would like using all the components of Flex. We
can also create reusable inline item renderers, but we will not be
building one in this tutorial because they are so similar to normal
inline. The code below is the new first DataGridColumn - I will explain
all this in just a moment.
<mx:DataGridColumn headerText="Song">
<mx:itemRenderer>
<mx:Component>
<mx:VBox verticalGap="2">
<mx:Image source="{data.art}" height="50" width="50" />
<mx:Label text="{data.artist + ' ~ ' + data.title}" />
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
For this column we are going to define the item renderer explicitly and
then create a component for the rendering inline. You always start by
defining it as an <mx:Component> and then adding the actually
rendering code to this. I added a VBox to align my other components and
narrowed the vertical gap for aesthetics. Inside of the VBox I have
added two components, the first of which is an image. We get the source
for this image from data which is how we refer to the current data
row and we can simply grab properties from it. The second component is a
Label in which we display the artist name and song title concatenated
together. There you have it, your first simple inline item renderer.
Now I mentioned reusable inline renderers. This is done very similar to
the technique we used above. The only main difference is where we put
our component code - to make it reusable we will move it up to directly
below the opening application tag and we need to make sure we give it a
unique id (which would be used later to refer to it). That will take
care of making it reusable and then to use it just set the
itemRenderer property equal to the id of the renderer component.
These item renderers are the most complicated to implement but are also the most useful. Hopefully everyone has had some small experience with creating custom components, the minimal amount of experience is needed. To create my rating item renderer I actually created two components, one for the star and one which puts all the stars together (actual item renderer). I will run through the star component first. This component, named "RatingStar.mxml", is fairly simple - it is based off of a Canvas and holds an Image component. The component has three states, one for a no star rating, one for a half star rating, and one for a full star rating. Each state sets the source to the appropriate embedded image. If you don't understand the concept of state for a component, don't worry - I'm planning for a tutorial on this later on. So a new file named "RatingStar.mxml" contains the following code. Note - the embedded images are just some I created.
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="20" height="20"
currentState="noStar">
<mx:Script>
<![CDATA[
[Embed("assets/nostar.png")]
private var noStar:Class;
[Embed("assets/halfstar.png")]
private var halfStar:Class;
[Embed("assets/fullstar.png")]
private var fullStar:Class;
]]>
</mx:Script>
<mx:Image id="imgStar" height="20" width="20" />
<mx:states>
<mx:State name="noStar">
<mx:SetProperty target="{imgStar}" name="source" value="{noStar}" />
</mx:State>
<mx:State name="halfStar">
<mx:SetProperty target="{imgStar}" name="source" value="{halfStar}" />
</mx:State>
<mx:State name="fullStar">
<mx:SetProperty target="{imgStar}" name="source" value="{fullStar}" />
</mx:State>
</mx:states>
</mx:Canvas>
On to the interesting part, creating the renderer component. This is a
custom component created in a file named "RatingRenderer.mxml". I based
this component off of the HBox component. From here we could take two
different routes to defining the component - we could have just built
the component using mxml and used the data property to access the
current row data just like the inline item renderer. But I choose to go
another route, most container components have the data property and
you can override the set function of this property. So basically when
the component's data is set - when the datagrid is passing the current
row data to the component - we can then use this data to modify the look
of the component. This is all done in Actionscript. Here is the code for
that:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" horizontalGap="2"
width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
<mx:Script>
<![CDATA[
private var _data:Object;
override public function set data(value:Object):void
{
_data = value;
var rating:Number = Number(value.rating);
removeAllChildren();
var ratingStar:RatingStar;
for(var i:uint = 0; i < 5; i++)
{
ratingStar = new RatingStar();
if(rating > 1)
{
ratingStar.currentState = "fullStar";
rating -= 1;
}
else if(rating > .5)
{
ratingStar.currentState = "halfStar";
rating -= .5;
}
else
ratingStar.currentState = "noStar";
addChild(ratingStar);
}
}
override public function get data():Object
{
return _data;
}
]]>
</mx:Script>
</mx:HBox>
Looking at the basic structure we have our HBox which has a couple
properties set, nothing out of the ordinary. Then we have some
actionscript and this where the magic happens: we override two public
functions set data(value:Object) and get data() and setup a private
var. Inside the set data(value:Object) function is where most of the
work happens. We start by setting our private var to the value passed in
by the datagrid and then figure out the rating by getting it from the
data passed in and converting it to a number. The next line is very
important, we start by removing all the children currently added to the
HBox so we start with a clean slate. Following this we loop through 0 to
4 (max rating - 1) and create stars to add to our HBox. For each star we
set the state based on the rating of the song. Lastly we add the star to
the HBox (again very important - as nothing will show up without it).
And there we have it a fully customized item renderer.
Wait, how do we use this complex thing now? Well that is the simplest
part - all we need to do is set the itemRenderer property of our
DataGridColumn to the name of the component to do the item rendering. So
in this case, we set it equal to RatingRenderer. The code for our new
DataGridColumn is below.
<mx:DataGridColumn headerText="Rating" width="125" itemRenderer="RatingRenderer"/>
Well that pretty much does it. If you want more info on the custom component item renderers you can check out the livedocs here. I hope this tutorial gives you some insight into the working of item renderers. Only thing left is to show you the entire source of the main mxml file:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="530" height="405">
<mx:Panel x="0" y="0" width="530" height="405" layout="absolute"
title="Item Renderers">
<mx:DataGrid x="0" y="0" width="510" height="365">
<mx:columns>
<mx:DataGridColumn headerText="Song">
<mx:itemRenderer>
<mx:Component>
<mx:VBox verticalGap="2" paddingLeft="5">
<mx:Image source="{data.art}" height="50" width="50" />
<mx:Label text="{data.artist + ' ~ ' + data.title}" />
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn headerText="Rating" width="125"
itemRenderer="RatingRenderer"/>
<mx:DataGridColumn headerText="Favorite" dataField="isFavorite"
width="75" itemRenderer="mx.controls.CheckBox"/>
</mx:columns>
<mx:dataProvider>
<mx:ArrayCollection>
<mx:Array>
<mx:Object title="Stairway to Heaven" artist="Led Zepplin"
art="/files/led_zep.jpg" rating="4.5" isFavorite="true" />
<mx:Object title="How to Save a Life" artist="Fray"
art="/files/fray.jpg" rating="4" isFavorite="false" />
<mx:Object title="Sinnerman" artist="Nina Simone"
art="/files/nina_sim.jpg" rating="5" isFavorite="true" />
<mx:Object title="Take On Me" artist="Aha"
art="/files/aha.jpg" rating="3.5" isFavorite="false" />
</mx:Array>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
If you have any questions or comments drop a line below. Also to make things a little easier here is a .zip file with all the source code for this tutorial.
Edit (12/10/2007):There have been a couple questions on how to center the checkbox in this example/tutorial. So I have modified the example above to have the checkbox centered and the View Source option is available if you right click the example.
But basically all that needs to be done is switch:
<mx:DataGridColumn headerText="Favorite" dataField="isFavorite" width="75"
itemRenderer="mx.controls.CheckBox"/>
To the following:
<mx:DataGridColumn headerText="Favorite" dataField="isFavorite" width="75" >
<mx:itemRenderer>
<mx:Component>
<mx:Box width="100%" height="100%" horizontalAlign="center"
verticalAlign="middle">
<mx:CheckBox selected="{data.isFavorite}" />
</mx:Box>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Source Files:
How will I get the object or instance of item renderer .. i need to change some property after the grid is formed .. after that I want to access all the properties of IR .. how can it be done ?
Can explain a little more what you are trying to do? Are you trying to change a property of the item renderer and how are you building the item renderer? There are a couple ways you could send data into the item renderer. You could bind to a model inside the item renderer and then simply update the model when you want to update the item renderer. You could also dispatch an event from the item renderer that you listen for at the datagrid level and update items from there also. So perhaps when the information is being displayed you could throw an event on the overridden set data function, now this would happen alot especially if you are changing the data frequently. But would be necessary if you want to customize the IR for each row. Let me know if I am getting closer.
I have the same question, im trying to access the itemrenderer in a tilelist that lies in a module.
moduleCollection[moduleName[i]].mod.child.listGenerator.itemRenderer: [object ClassFactory]
my only attempt has been to make an instance of the itemrenderer :
var factory:ClassFactory = new ClassFactory(moduleCollection[moduleName[i]].mod.child.listGenerator.itemRenderer);
and then maybe to a with(factory) or just factory.property
but i get error : cannot convert classfactory to class.
Regards Niclas
solved
How?
Do you know how to center align the checkbox control in the datagrid?
Thanks!
Yeah you can do this by switching the checkbox itemrenderer from a drop-in to a inline and simply add a container in which the checkbox would be centered in. So inside the your datagridcolumn you would have your item renderer which would have say a Box which would be the correct horizontal and vertical alignments, which inside it would have the checkbox inside it. Let me know if you need more information than that.
HI,
To align the checkBox we need extend checkbox control and align it in the updateDisplayList overriding function....
Saravanan, that is an extreme solution, you do not have to do that. You can do exactly what I said in my last comment. I have added an edit to the post to show this.
if you only wanted a simple way to align the checkboxes to horizontal center...
textAlign="center"
eg,
Hi Fattest please tell me how I convert the ajax grid table into flex data grid table , here i am able to insert a table in existing jsp page but not able to fetch data from database (I mean from business service class)I am not able to get the data in datagrid
what i need to do is create a DataGrid that will display 3 columns in the first column i need it to display a DateField in the second a TextInput and in the third i need to show 3 NumericSteppers (for time). i can do this if i populate the datagrid with data first, but i dont want data in there to start off with i want the user to input data there. i was thinking of using a grid with a repeater, but i dont see how that would work. i need to be able to input x amount of entries into the fields and it seems that a datagrid would work perfectly for that if i could get the items to first remain empty then figure out how to add new rows after the first one has been populated. i have spent a long time trying to figure this out and i have gotten to the point where i dont know what would be the best solution.
I have an array collection that populates a datagrid. I would like to insert a button renderer for updating the row if specified columns are blank. Can you help me with where to place the condition statements that would control each row of the datagrid?
For example... If DG index 0 column C is Blank insert a button at DG index 0 column C.
Yeah I think the simplest solution, Mark, would be an item renderer. Just override the set data and change the what is being shown in the column. I would probably just have a label and a button and show/hide them appropriately. I would check if the corresponding property is null or "" in the override function.
Let me know if you would like to see an example.
Hi there. I'm trying to accomplish something with Item Renderers that I just can't figure out. Hopefully you can shed some light on it as I'm fairly new to Flex and AS3.
I have an XML file which details a list of resources. Each piece of resource has a series of audience tags which detail what audience the resource is intended for. Something like:
no yes yes
What I want one of the columns to display is a list of all the audiences that the current resource has a "yes" value to. So for the above resource the column should display "audience2 audience3" in a text box or similar.
I've tried several different ways to accomplish this. Writing code in the tag of the renderer doesn't seem to allow me to access the "data" variable that the renderer gets sent. Overriding the set data function gives me a #1009 error whenever I try to access the object it gets passed. I just can't figure it out. Any help you could give would be greatly appreciated. Thanks.
Ahem, the above example code has gotten rid of the tags I put in so just ask if you need me to re-do it (and tell me how to type it :P)
Unfortunately our comment system strips all tags before posting it. It's something that's been on our list of things to fix for a long time. For now, you can use most of the html special characters to get the job done. < and > will make the tags \< and >.
Thanks. The example code is:
\ \no\ \yes\ \yes\ \
Wow. I'm fairly new to Flex programing and was really struggling with the renderer stuff til I read your tutorial. That's after poring through the adobe docs, reference books, and a bazilion blogs. Thank you very much
How can i have two or more item renderers in the same column?? i have been searching the for long time, but cant find any thing.
can you help me???
thank you so very much for all these tutorials! i couldn't imagine learnig all that stuff by myself until i checked out your stuff and started to build some small applications with your code and tried to adapt them to my needs...
eg,
great 101 tutorial!
great tutorial - I was really struggling with an itemrenderer for a chart that would display different images depending on the values in the chart - your star renderer does the job brilliantly!
Hello, nice tutorial!
Unfortunatelly I didn't found the solution for my problem :(. Daniel asks for it before... How to use different item renderers (or editors) in the same column of DataGrid? Does anyone know how to do it?
Yeah I have built something for handling this issue luk. I basically built a item renderer that basically looked at the data and basically built the needed controls. I also have an idea for extending the datagridcolumn to handle this. I will post something soon on this.
i am using a datagrid and set background color of one column using the itemrenderer which is a action script file that checks condition and based on that set's the backgroud. Now when the value of arraycollection which is the dataprovider of the datagrid is changed, it still shows the old background color of the earlier arraycollection value.how to solve this?
Hi, Your tutorial has helped me understand DataGrid better. Even i m looking for the same - having more than 1 itemrender in the same colum - 1)default text box and 2)color picker. So if you could share the example that u are mentioning here it will be very useful
Thanks in advance, Mohana
Thanks "The Fattest".... it really guide me to understand the itemrender more.
thanks. cheers!
Hi,
Great article - thanks for that. The processing logic above doesn't seem quite right ... even in your own example Nina gets 5 stars yet the datagrid does her an injustice in assigning 4.5. I made an adjustment as follows:
Hi.. is it possible to access or change properties of control which is used in itemrenderer. Actually am using image control in DataGrid as itemrenderer and i want to change Load property and height property of image control after the loading of datagrid.. Thanks Rohini
Yes this is possible. Can you achieve what you want by changing these properties in set data function, which gets called each time the data property is set, of the item renderer.
hi Fattest,
I jus need to do as what u said in ur comment. could u please send me any useful links for that.
I do have a advancedatagrid with checkbox, textinput, image. as I change the checkbox sate , and inputbox data the image has to change. and the data in the dataprovider has to update.
Thanks
Awesome tutorial. Very well written and very very helpful.
hi i m facing a problem with button as my renderer inside my datagrid.. i want to make it disable at some point of tree change... its not coming properly.. help me
Purnima, I need a little more details on what your trying to accomplish. So you want to disable a button when you update a tree control? The button is in a datagrid itemrender?
see friend the privious exmaple, you have use the checkbox as item render,what i have some problem in that example,after i select the three two checkbox ,i want to sort the data in rating rater, but the time changed
Does anyone know of a way to disable the reuse of itemRenderers? I have a small DataGrid and I need all the cells painted at all times …
This is something inherit inside flex list component. If your looking for a repeating component that doesn't reuse itemrenderers you need Repeater component.
Hi, I'm need an itemRenderer that will check if a datafield in a datagridcolumn is not equalto a variable and then change the datafield to ****** or blank if it isn't. I can't seem to figure out how to make one I guess. Thanks Nathan
Did you create an itemRenderer that is a label or a textinput? If it is a textinput then there is a property displayAsPassword which will make it asterisks. If label then you have to override the set data function and check then the value. If you have some example code toss it up here, I will take a look at it.
Hi
I am using Advanced data grid to show some values i need to show default sorting icon in header. because the first column is having default sorted values.
with thanks.
vbajaj@logicielinfosys.com
I'm trying to vertically and horizontally center text in a cell. I used the code with the checkbox and it centers fine. However I also want to have a background colour. I used to have this.opaqueBackground="blah" on a Label but now I'm using Box for the centering and now it only colours around the text and not the whole cell... Hope you can help. Thanks!
The examples above were very helpful. My question is when should you use an RendererProvider vs ItemRenderer.
Very nice example and extremely useful and helpful. Thanks a lot!
Of course, one question though - is it still possible to access methods in my script?
Typically when calling methods from within an inline itemRenderer I would prefix the method with "outerDocument." - to back out the scope to the main context.
Is something similar possible in this example?
Thanks again!
UPDATE:
So as it turns out what I needed was
.
worked when the itemRenderer was inline with the other xml but in a custom component I needed to use
.
NOTE - the method you are calling must be public.
Apparently, you can also do it like:
Just thought others might find that useful.
dude you are my hero ive been at this for days trying to figuere out how to do this and just post clearly stated the parentDocument.!!! thank you im finally going to be able to move on with my project now!!!
Hi,
If I use a CheckBox for one of the columns, how can I listen to its change event?
I'm trying to figure out a way to have the item renderer talk to its row in the data grid plus an event external to the item render talk to the item renderer. Specifically, if I have radio buttons in the item renderer, I want if one is clicked to change a property in the data grid row. Then, if a 'Select all' button is clicked on the panel, I want to be able to go into each row of the data grid and have the first radio button set to selected. Here is my item renderer:
It talks to its row no problem when the button is clicked, but how do I make the row set the value of the radio button?
On an item renderer a property named
datawill be set. This can be used for binding so if the property on the row you want to bind to is named "mySelected" then you would do something like:You can also use the
dataproperty to set the value on too. So you really don't need to usethis.parent.parent.selectedItem.PERMISSIONyou can just usethis.data.PERMISSION.Hi,
I am having a problem binding XML to my itemRenderer I would apreaciate any light anyone could shed. (Flex 4)
My xml:
MY FLEX
My Item Render
And thats about it, but it will not bind correctly for love or money, any ideas?
Please and thank you in advance.
Hi , nice article. I got stuck with some problem. I am using flex 4.1, advanced datagrid, remote component of rpc to get data from back end. I am using Itemrenderer, in which i have a toggle pin, to change the display according to data. I need to flip the state of togglepin when user clicks on togglepin( when user clicks on this , i need to make a service call in order to get the updated data from back end). Here I am using parentDocument.selectedItem to capture that particular row object. My problem is when i click first time on toggle pin it is not able to set that row ID but for second click it was able to set the correct ID of the corresponding row. any help
Hi!
I'm trying to learn Flex, and i think it's loads of fun, but i have som troubles understanding some parts. Im doing a movie database just for learning purposes and i got the database ready, i can put in title, producer and so on in it and got a workign validation too.
Im just trying to figure out how to get the rating value from database and use it in the star rating script, instead of showing 3.5 in rating in the datagrid i wanna ofc show 3.5 stars. Any ideas?
I think i have to somehow bind the rating value from the database (or datagrid) and pass it to RatingStar.xml, coz i get a warning at the moment "Data binding will not be able to detect assigment to fullstar/halfStar/noStar"
Would appriciate if someone could point me in the right direction.
i want to use the itemrenderer and still edit a data column and on the completion of the editing .the data should be shown in different colors according to the value of the data
thanks, very helpful
Hi, how can I write the following code in ActionScript?
Hi, I'm new to coding! I have three rotating images on my website and will like to add a fadein effect. How do I do that with javascript? Thanks!
Hello,
This example is great, but there is a missing functionality that I really like to know how it can be achieved. If I wanted to do some action when the user clicks on the "Favorite" checkbox, where I could place the call of the action(method)?
In this example we have:
I cannot find where we could add an action to the checkbox click! Please help me!
Thanks in advance
i want to know if i can use itemRenderer in other component besides the DataGrid for example TileList
Thanks for your efforts, I tried this, however hitting issues, and tried in another way which is working for me, code posted at my blog - http://bbso.wordpress.com
Hi, I have 2 questions. 1.I would like to fetch the values for my Tree from the Database. I'm able to fetch the values but I don't know how to get them in a hierarchical manner. 2. I'm using checkboxes in my tree view to select them for charting purposes. While doing so, I would like to send the values of checked boxes to fetch the corresponding data from the DB. how do I do this?