The following example formats a column in a Flex DataGrid and uses a custom item renderer to color the text red in a cell if a price is below $0. If the item is greater than $0, the test is displayed in black. The price column is also formatted using a custom label function, which uses a CurrencyFormatter, and finally, the data grid column uses a custom sort function to properly sort numeric columns.
Full code after the jump.
<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/20/formatting-a-flex-datagrid-control-using-a-custom-item-renderer/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.utils.ObjectUtil;
private function price_labelFunc(item:Object, column:DataGridColumn):String {
return currencyFormatter.format(item.@price);
}
private function price_sortCompareFunc(itemA:Object, itemB:Object):int {
return ObjectUtil.numericCompare(itemA.@price, itemB.@price);
}
]]>
</mx:Script>
<mx:XML id="itemsXML">
<items>
<item name="Item 1" price="1.32" />
<item name="Item 2" price="-12.23" />
<item name="Item 3" price="4.96" />
<item name="Item 4" price="-0.94" />
</items>
</mx:XML>
<mx:Style>
.centered {
text-align: center;
}
</mx:Style>
<mx:CurrencyFormatter id="currencyFormatter"
precision="2"
useNegativeSign="false" />
<mx:DataGrid id="dataGrid" dataProvider="{itemsXML.item}">
<mx:columns>
<mx:DataGridColumn dataField="@name"
headerText="Name:"
headerStyleName="centered" />
<mx:DataGridColumn dataField="@price"
headerText="Price:"
textAlign="right"
headerStyleName="centered"
labelFunction="price_labelFunc"
sortCompareFunction="price_sortCompareFunc"
itemRenderer="PriceLabel" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
PriceLabel.as
package {
import mx.controls.Label;
import mx.controls.listClasses.*;
public class PriceLabel extends Label {
private const POSITIVE_COLOR:uint = 0x000000; // Black
private const NEGATIVE_COLOR:uint = 0xFF0000; // Red
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
/* Set the font color based on the item price. */
setStyle("color", (data.@price <= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR);
}
}
}
View source is enabled in the following example.



Hi,
Thanks a lot man !
Hi Peter,
Thanks for the example! :)
Do you know how to create an item renderer in a datagrid column that creates different components based on the data?
For example,
column 1…….column 2
————————-
item 1………[checkbox]
item 2………[checkbox]
item 3………[combobox]
item 4………[textinput]
item 5………[textinput]
data:
array = [{label:’item 1′,type:’checkbox’},etc]
When I scroll or sort the headers everything screws up.
How do I center align a checkbox inside a datagrid? It always aligns left…Please help.
Richie,
I’m not sure, but check out Alex Harui’s excellent blog entry, “More Thinking About Item Renderers”, which has demo and full source code.
Peter
Could you say me build number of Flex complier. I got another behavior of your example. Price column and cell have the same align - “right”.
My build number: Version 2.0.1 build 155542.
Thanx.
sinnus,
All of the examples in this blog were built with various beta/nightly builds of the Flex 3 SDK.
Peter
@Ritchie,
I’ve centered a checkbox in a datagrid column before by adding an HBox around it and using horizontalAlign=”center”
Hey Now,
Nice post it was helpful to me.
Thx 4 the info,
Catto
An improvement to the label function might be to change the return currencyFormatter.format(item.@price); t0 return currencyFormatter.format(item[column.dataField]);
This should make the label function usable on any column that can be formatted as currency rather than hardcoding in the column field.
Hi Peter, how can I do to change the background of entire line, based in some information in the fields? Thanks.
@judah (6 months later),
i think you need to override the set data accessor - the same instances of the renderer get reused, you’ll need to change the contents of the view hierarchy when the data changes,
Flex newbie… Is there a way to make this package more generic so the colomn nmae doesn’t have to be embedded in the package? This way any column that needed this formating “itemRenderer” could use this package.
Thanks for all of your examples!!
Greg C,
Try something like this:
package { import mx.controls.Label; import mx.controls.dataGridClasses.DataGridListData; import mx.controls.listClasses.*; public class PriceLabel extends Label { private const POSITIVE_COLOR:uint = 0x000000; // Black private const NEGATIVE_COLOR:uint = 0xFF0000; // Red override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); var dField:String = DataGridListData(listData).dataField; /* Set the font color based on the item price. */ setStyle("color", (data[dField] <= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR); } } }Peter
Thanks Peter. Worked great!
Peter,
I am trying to apply your above example to similar code for another use of a datagrid itemRenderer. So I was wondering if you could point me in the right direction if I wanted the value of an external Control to affect the threshold point of the values that are colored.
So if I had an hslider it could be used to dynamically change the value of the cut-off point of the colored items in that column of the datagrid.
So basically instead of:
setStyle("color", (data[dField] <= 0) ? NEGATIVE_COLOR : POSITIVE_COLOR);it would be:
setStyle("color", (data[dField] <= X) ? NEGATIVE _COLOR : POSITIVE _COLOR);X being the value that would be represented by the position of the hslider.
Does this make sense?
Since I am new to this whole package/class thing I am not sure how to access that external value inside of the package that is being called by the itemRenderer of a grid column.
Thanks again!
Peter, Once again sorry for the double post… Any thoughts regarding how I can go about passing a dynamic value from a control into this package? I have tried a couple things and none of which seem to work.
Thanks,
Greg C
Greg C,
Probably not the best solution, but you could try using
Application.application.slider.value. I’m not sure how well it would work since the itemRenderers wouldn’t necessarily be updated when the slider changes.Peter
Some more great info, thanks for the tips.
Note that a similar solution (for background-color) is posted by jlafferty at:
http://butterfliesandbugs.wordpress.com/2007/07/11/using-an-itemrenderer-to-change-the-background-of-a-datagrid-cell/
Hi guys,
In this example, how can be sorted the price column as a number?
Any ideas?
Janet
janet,
The price column is sorting as numbers, isn’t it?
Peter
Nope, when the prices are loaded you get ($1.32, $12.23, $4.96, $0.94), if you sort the price column you get ($12.23, $0.94, $1.32, $4.96) instead of ($12.23, $4.96, $1.32, $0.94), and if you sort again to get the numbers from descendant to ascendant you have($4.96, $1.32, $0.95, $12.23) instead of ($0.95, $1.32, $4.96, $12.23)…
janet,
Interesting. I see the same default sort as you (1.32, -12.23, 4.96, -0.94) — the items are unsorted and appear in the same order they were specified in the data provider.
If I sort by price (descending), I get the following: -12.23, -0.94, 1.32, 4.96 (or Item 2, Item 4, Item 1, Item 3). This sort is correct since the biggest negative values are first and the biggest positive values are last.
If I sort by price (ascending), I get the following: 4.96, 1.32, -0.94, -12.23 (or Item 3, Item 1, Item 4, Item 2). This sort is correct since the biggest positive values are first and the biggest negative values are last.
Actually, are you sure your numbers are right? 0.94 and 12.23 are both negative numbers. So I wouldn’t expect the price column to sort as 12.23, 4.96, 1.32, 0.94 since both 0.94 and 12.23 are negative numbers in the data provider. I’d expect 4.96, 1.32, -0.94, -12.23.
Peter
hi,
i have developed a similar example. the difference is that my item renderer is a linkbutton extend class. The override function is the next:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); var spattern:String = listData.label; var tic:TextImageClass = new TextImageClass(spattern); if (tic.tranform()) { this.setStyle("paddingRight",Number(35)); if (tic.displayObject != null) { this.setStyle("icon",tic.imageClass); this.labelPlacement = ButtonLabelPlacement.LEFT; } if (tic.uiTextField != null) { this.label = tic.uiTextField.text; } } }my problem is when i sort a column. When i click the column header, the data rows are changed but not sorted… but i move the mouse cursor over the rows… magically… the data in the columns are going to appearing sorted.
any idea?
thanks, congratulations, it´s a great website
Hello,
Thank for this very interesting example.
If a change the source with an arraycollection, what kind of modifications i must do in the PriceLabel.as field ?
Thanks
Best Regards
Pierre,
In PriceLabel.as, it looks like I hard-coded the column data field (
data.@price) into the item renderer. Of course, you could create a new subclass for each different data field (CostLabel.as, etc.), but that would probably not be the best approach.I think the better approach would be to look at my coworker Alex Harui’s solution to this, as he is ridiculously smarter than I am: “Thinking About Item Renderers”. Specifically, I was reading the Text Color and Styles in Item Renderers section. He shows how you can extend both the DataGridColumn and DataGridItemRenderer classes, and create a custom
stylesFunction()method which evaluates the data in a column without hard-coding specific column names.Peter
Can an ItemEditor dispatch their own events? If so, how do you set an event listener to capture the event?
I’m trying to use similar code but have the logic based on the value of an attribute “D” in my xml data but I cannot figure out for the life of me how to access the attribute in the .as file for the current column (I’m using the renderer for multiple columns). My XML looks something like this:
<cols>
<colA D=”1″>123</colA>
<colB D=”2″>123</colB>
</cols>
using data..@D gives all D values for the current cols node (i.e. “12″). Can anyone advise?
Thanks!
Sussed it!
data[DataGridListData(listData).dataField].@D);
I have try your example.Very useful.Thanks lots. I still have one question and hope you can help. Now I have 2 string, lets say AAA and BBB which I want to change their color out of many data. I try to use :
setStyle(”color”, (data.id == “AAA”) ? NEGATIVE_COLOR : POSITIVE_COLOR);
setStyle(”color”, (data.id == “BBB”) ? NEGATIVE_COLOR : POSITIVE_COLOR);
but it only change the color of BBB.
So what should I do to change both field?
thanks
Hi,
Very nice blog … Is there any way to change the text color of the entire row of a datagrid based on data with out creating a itemrenderer for each column. I have around 10 columns, and want to change the color of text to red or green based on some data.
Thanks,
Shreyas
Is there any concern of this method being a performance hit? I put a trace statement in my updateDisplayList() in my custom component while I was getting things going. I noticed that if I had 10 items, on load i got 20-30 traces. If I move my mouse over I get more traces. Same with a select. I understand why this happens, but is there not a way to set it and forget it? Does the DG loose the settings each time it redraws?? I am still sort of amazed that there isn’t just a property to set for a row color.