Change DataGrid cell background with an itemRenderer

This is one of the most common questions that I’ve seen in various forums with regards to itemRenderers…. “How do I change the background color of my DataGrid cell depending on my data?“. As usual, the answer is to use a custom itemRenderer. In the following example, I am using the same itemRenderer for 2 of the 3 columns in the DataGrid. The itemRenderer checks if the data displayed in the cell is over the value 15, if so, it turns the background RED.

Demo: datagrid_reusable_itemrenderer.swf

Sample Code: datagrid_reusable_itemrenderer.mxml, BackgroundComp.as, airlines.xml

By default, a DataGridItemRenderer does not have a background fill. Therefore, there isn’t a simple style to set on a renderer to make the background some color. Instead, we need to draw our own fill for the renderer in a custom updateDisplayList function. In our renderer, we use this code:

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);var g:Graphics = graphics;
g.clear();
var grid1:DataGrid = DataGrid(DataGridListData(listData).owner);
if (grid1.isItemSelected(data) || grid1.isItemHighlighted(data))
return;
if (data[DataGridListData(listData).dataField] > 15)
{
g.beginFill(0xCC0033);
g.drawRect(0, 0, unscaledWidth, unscaledHeight);
g.endFill();
}
}
About these ads

36 responses

  1. this doesnt seem to work when setting the itemRenderer via ActionAcript

  2. found the answer . . .
    should use:

    myGrid.itemRenderer = new ClassFactory(BackgroundComp);

  3. Yup. The itemRenderer and itemEditor properties are of type IFactory. When you set these properties in MXML, the MXML compiler automatically casts the property value to the type ClassFactory, a class that implements the IFactory interface.

  4. Can you make the background color flash??

  5. d, where did you place the below line?
    nodes.itemRenderer = new ClassFactory(ChangeBGColor);

  6. ef,

    You can set an itemRenderer at runtime anywhere in your code. For example, you might set it on the initialize event of your DataGrid or List.

    There are a bunch of examples in the Adobe Developer’s Guide that can be found here:
    http://livedocs.adobe.com/flex/2/docs/wwhelp/wwhimpl/js/html/wwhelp.htm?href=Part2_DevApps.html

    Look under the subject: Flex 2 Developer’s Guide ->Customizing The User Interface -> Using Item Renderers and Item Editors -> Creating an item renderer and item editor -> Setting the itemRenderer or itemEditor property in ActionScript

    There is an example there of just what you want.

  7. Thanks for the response and the references Joan.
    Of course I thought this is a working sample, but taking it to debugger shows that listData is null.

    I just could not figure out why clicking your datagrid_reusable_itemrenderer.swf does work, but when I copy your example to my environment it does not. Is there a difference between your generated swf file and the mxml/as files?

    Thanks,
    ef

  8. No difference, I think. I just downloaded the files, created a new Flex project and debugged. It seemed to work for me just fine. Make sure you grab the data file too since the example uses an HTTPService to load the xml as data for the DataGrid.

  9. Thanks Joan. My error. Worked like a charm.
    ef

  10. Hello all, I am trying to do something similar to this, except I want to change the value of a whole row based on the value of one column. Is there a way to do that?

    1. Change if (data[DataGridListData(listData).dataField] > 15) to

      if(data["YOURCOLUMNNAME"] == “YourValue”)
      Also, play around with the drawrect co – ordinates

  11. Thanks for this wonderful example. Unfortunately your implementation also overrides the auto-resizing of a cell’s height should the data take up more than the default space of a cell. I’ve tried a number of ways to overcome this to no avail. Do you have any insights as to how to regain the ability to expand the height of each cell (more accurately, each row)? Thank you again.

  12. That was a life-saver! I thought this was going to be nigh impossible to do! Thanks!!!!

  13. Just for the info:

    The gaps, which are appearing between rows, are coming from paddingTop and paddingBottom styles of ListBase (though they are not used in ListBase directly, but in DataGridBase)

  14. Found that if you offset the “drawRect()” a little the gaps disappear. Don’t know if this works for all styles and settings, but it worked form me no matter how high I set the rows to be.


    g.beginFill(color);
    g.drawRect(0, -2, unscaledWidth, unscaledHeight+4);
    g.endFill();

    Tried different values and these worked the best.

  15. hi..
    i want fill color based on column and row index value.. how can i doing? Pls help..

  16. Instead of comparing the data value with 15 If i want to do comparison of two column value and set the row value red if column1 value is less than column2 value then how can i do?

  17. hi !

    i don’t understand wgy you use a drawning to just change the background with itemrender ?
    if i was you, i will create a itemrenderer based on a Vbox, includind a Label. And change the backgroundcolor property of the vox !
    the result is the same and easier, isn’t it ?

    1. @Michael, if you will only have a couple of itemRenderers in your List or DataGrid and are not concerned with performance, then, using one of the containers to create a background for an itemRenderer is fine. However, the Flex containers like VBox, Canvas etc. have a lot more heavyweight functionality than you need. Therefore basing your itemRenderer off on a component like Label is lighter (but, yes, a little more work). You will start to see a lag in scrolling if you use a container as itemRenderer when you start having many more rows of visible data.

  18. hi Joan,
    since i needed a function do render the background of a cell, I have implemented your function (used switch/case in BackgroundComp.as) because of multiple conditions).
    However, I need to be able to render a cell based on the content of another node. How do I extend the Background.as file such that I can define e.g. a Datagrid column name to use that as reference for rendering. ?

  19. This is a good example but ItemRenderer works only with small amount of data. If you have a huge advanceddatagrid like say 50 columns and 1500 rows and you try to use an itemRenderer on it , your application will be really slow when you try to scroll horizontally or vertically. I had a similar advanced datagrid where I used itemrenderer and setStyle to show +ve numbers in blue and -ve numbers in red and it runs very slow.Let me know if you have a better solution to this problem or make it run faster. Try it when the data is getting updated every 10 seconds

  20. How can I get rid of the not colored horizontal lines between the cells?

  21. Thank you for this example.
    I want to know how can I change color of selected cell of advanced datagrid.
    I will be happy to see your quick answer.

  22. Thank for the nice article. However, I try the example, but it doesn’t work.

    I read your comments and I don’t know where to but the missing line/code and what does it mean?

    the missing code/line:
    myGrid.itemRenderer = new ClassFactory(BackgroundComp);
    or
    nodes.itemRenderer = new ClassFactory(ChangeBGColor);

    what does myGrid or nodes mean (are they function) and where are they defined?
    what does BackgroundComp or ChangeBGColor and where are they define?

    where to put the above code?

    If you could please help in that and I wish by solving it, the example will work.

    best regards,
    Ali

  23. If you want to get an alternating custom color, here a little hack:

    g.beginFill(0xCC0033,0.02);

    The second beginFill param is the alpha. By setting it low you get the alternating datagrid bg color and your custom item renderer bgcolor to blend, giving an alternating custom color background :)

    It’s a hack but it works :)

  24. [...] found this great article that gets me pretty close, but I am a bit [...]

  25. Joan

    thank you for posting this (so many moons ago, yet still so pertinent!). I’ve copied your code (with slight modifications) to color a cell in my DG that is pre-selected via some edit boxes and it works like a charm. Two issues, though. 1) itemRenderers seem to take a HUGE amount of time if the DG is fairly large (say 6 columns by 40 rows), even if most cells actually end up rendering in the usual way. 2) It seems like I need to call an invalidateList to get the cell indices to update properly – which is annoying since this takes a huge amount of time too. Any thoughts on to get around these?

    thanks again

    1. @Jon, There is another example of an itemRenderer with a background on Alex Harui’s blog: http://blogs.adobe.com/aharui/2007/03/thinking_about_item_renderers_1.html
      This one extends DataGridItemRenderer which I believe is more lightweight than Label (which mine extends), so, you might get better performance with Alex’s itemRenderer. Good luck!

  26. [...] name, rpc events I wrote another question about this some time ago, then found this article (which is easy and great), implemented a solution and shut the question. Turns out that when my [...]

  27. I made a solution for alternating column color for the columns you choose, here is the link
    http://www.flex4ex.com/?p=9
    Click here

  28. One thing to keep in mind with this type of solution, is that if values in your datagrid are apt to change, this does not change the cell background back to the “default”color. In other words, if a value drops to 15 or less in the example, the background color will remain the same. The simplest solution, of course, is to change the background to a predetermined ‘default’ color when the value is 15 or less, but the problem gets kinda sticky if you have to honor different skin settings.

  29. Hi …Nice solution but i had different problem then i got solution i hope it may help for others who are searching for same problem…

    I got solution for coloring one cell background in one column based on comparing other cell value in different column

    suppose i have two columns 1. ASR_IC , 2. THR_ASR_LEVEL. My requirement is comparing second column that is thr_asr_level values I need to color the first column corresponding row of the second column value, say second column has 1,2,3,4 level values exist. solution as follows

    First take dataprovider into Array but actually dp will be 3 dimensional array to get value, but first take into single dimensional array and legth u take in second dimensional dp[0].length into for loop maximum count. Once started for loop with three dimensional array of dataprovider u get value compare with level values could be (1,2,3,4 assume these values exist in second column i.e. thr_asr_level) then start searching on first column using Advanceddatagridlistdata(listData).datafield so ur itemreneder will searching on first column there u write the background coloring…here twist is corresponding loop i value is the rowindex …..so corresponding row u can catch…that is it.. I hope thise will help u.

    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    var g:Graphics = graphics;
    g.clear();

    var grid1:AdvancedDataGrid = AdvancedDataGrid(AdvancedDataGridListData(listData).owner);
    if (grid1.isItemSelected(data) || grid1.isItemHighlighted(data))
    return;

    var dp:Array = Array((listData.owner as AdvancedDataGrid).dataProvider);
    var rowtotal:int = new int(dp[0].length) ;

    var i:int= new int(0);

    for (i=0; i < rowtotal; i++)
    {

    if (dp[0][i][THR_ASR_LEVEL] == 1)
    {
    if( (AdvancedDataGridListData(listData).dataField.toLowerCase() == ASR_IC.toLowerCase()) &&
    (AdvancedDataGridListData(listData).rowIndex == i) )
    { g.beginFill(0xFF0000);
    g.drawRect(0, 0, unscaledWidth, unscaledHeight);
    g.endFill();
    }
    }
    }
    }

    1. Hi Mahesh,
      I’m novice in Flex. I was looking for this solution, but i’m unable to access the column
      Error:
      Description Resource Path Location Type
      1120: Access of undefined property Album.

      Could you pls help
      Thanks in advance

  30. HI thanks for the post
    I want to insert button in one cell of a list and I am using an itemrenderer. It inserts radiobutton in all cells of the list. is there any method to do that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: