Accessing DataGrid ItemRenderers

Skill

Accessing DataGrid ItemRenderers

Posted in:

In order to do a lot of crazy things with the Flex DataGrid you may need to access the item renderers. Today I am going to show a quick and easy way to get to the array of item renderers for the entire DataGrid or any list based component. Now recently I got a comment asking about how to change a certain font style of the selected row. There are a couple ways to achieve this. I am going to show how to do this using the item renderer array. This tutorial is about how to get to that entire item renderer list.

So the first thing you can take a look at is the example application that I built to do this. The demo is as simple as it gets for showing off this functionality. I did however make sure that this code works if there is enough data to make the grid scroll. You can look and download the DataGrid Selected Row Source if you want/need to.

Get Adobe Flash player

Now I should warn you that the technique I use to bold the selected row isn't the best method for doing it, a later tutorial will go over another method. One item to think about is that it is hard to know the data in each renderer all the time so there are times in which this method will blow up. With that being said, let's create a custom DataGrid. The code for this class is below and all it is going to do is make a public property to expose the list of item renderers for the entire grid.

package
{
  import mx.controls.DataGrid;
  import mx.controls.dataGridClasses.DataGridHeader;

  public class CustomDataGrid extends DataGrid
  {
    public function get listRendererArray():Array
    {
      return listItems;
    }
  }
}

The new DataGrid we just created will be used in our demo which has an interface setup with the following code. You will notice I have a couple events on the DataGrid hooked up and I will go over these in just a second.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
   layout="absolute" creationComplete="init()" width="300" height="250">
  <local:CustomDataGrid id="dg" width="100%" height="229"
     dataProvider="{items}" sortableColumns="false"
     change="updateRowStyle()" scroll="updateRowStyle()">
    <local:columns>
      <mx:DataGridColumn headerText="Column 1" dataField="c1"/>
      <mx:DataGridColumn headerText="Column 2" dataField="c2"/>
      <mx:DataGridColumn headerText="Column 3" dataField="c3"/>
    </local:columns>
  </local:CustomDataGrid>
</mx:Application>

You will notice the change and scroll events need to be hooked up and to the same function even. Also the init function needs to be created. Well go ahead and check out our Script tag below.

<mx:Script>
 <![CDATA[
   import mx.collections.ArrayCollection;
   
   [Bindable]
   private var items:ArrayCollection;
     
   private function init():void
   {
     items = new ArrayCollection();
     items.addItem({c1: "i1 c1", c2: "i1 c2", c3: "i1 c3"});
     items.addItem({c1: "i2 c1", c2: "i2 c2", c3: "i2 c3"});
     items.addItem({c1: "i3 c1", c2: "i3 c2", c3: "i3 c3"});
     items.addItem({c1: "i4 c1", c2: "i4 c2", c3: "i4 c3"});
     items.addItem({c1: "i5 c1", c2: "i5 c2", c3: "i5 c3"});
   }
     
   private function updateRowStyle():void
   {
     var rowRenderers:Array = dg.listRendererArray;
     for(var i:int = 0; i < rowRenderers.length; i++)
     {
       if(rowRenderers[i].length > 0)
       {
         if(dg.isItemSelected(rowRenderers[i][0].data))
         {
           for(var j:int = 0; j < rowRenderers[i].length; j++)
           {
             rowRenderers[i][j].setStyle("fontWeight", "bold");
           }
         }
         else
         {
           for(var j:int = 0; j < rowRenderers[i].length; j++)
           {
             rowRenderers[i][j].setStyle("fontWeight", "normal");
           }
         }

       }
     }
   }
 ]]>
</mx:Script>

The init function should be pretty easy to follow. The updateRowStyle function on the other hand may need a little explaining. First you will see I grab the list of renderers from our custom DataGrid component. Next I loop through them and check to see if the data from each is the selected data and if so we update the style on the renderer, otherwise we set the style back to default. A couple little nuggets to look at is that I actually check to see if rowRenderers[i].length is above 0. I do this to make sure that the row actually has renderers and data. Then each item in rowRenderers is actually an array of renderers for that row. So in order to update the entire row's style I have to loop through them and set the style on each one. That pretty much takes care of all the heavy lifting.

I will however advise anyone looking to do this in a production environment to wait for my next tutorial where I will give a much better method of setting styles on selected rows. This is a good solution though for anyone building demo apps or just need a stop gap solution. Also we learned how to get to the entire list of item renderers for a list based component, which will allow you to wreak havoc on your lists, so have fun. If anyone has any questions or concerns feel free to leave a comment.

Perk
03/10/2009 - 15:11

Hi Fattest,

Just wanted to comment on how useful this post is. Thanks. I have also used this with custom itemRender's to do cool stuff like enable/disable buttons in DataGrid columns, switch images, etc.

reply

rocheking
03/16/2009 - 17:49

Hi I'm getting a lot out of your posts on item renderers. Thanks. I'm hoping there's an easy answer to the following. Sorry for the length!
I have a datagrid. On creation I call a function that loops through some XML data to create my column array.
For each iteration I set the item renderer to use a custom component.
In shorthand it's:
for each child in myXML {
col = new DataGridColumn();
col. etc. to set some properties...
col.itemRenderer = new ClassFactory(myRenderer);
}

You can see, I use the same item renderer for each column (called myRenderer).

Here's some simple data. For simplicity, let's pretend that all I want my item renderer to do is output the data as a string.

<row id="row1">
  <columnA>A1 </columnA>
  <columnB>B1 </columnB>
  <columnC>C1 </columnC>
</row>
<row id="row2">
  <columnA>A2 </columnA>
  <columnB>B2 </columnB>
  <columnC>C2 </columnC>
</row>

In myRenderer I have something like:
<mx:TextArea id="output" text="{data}"> which outputs the whole row1 node repeated in each cell. In row1 it's etc. repeated in columns A B and C.

Or I can have:
<mx:TextArea id="output" text="{data.columnA}"> which outputs A1 B1 C1 repeated for every cell in row 1 and A2 B2 C2 for every cell in row 2

I'm obviously after the syntax that allows me to output the correct text for each column something that might be like -- text="{data[currentColumn]}"

I'm wondering if that's not possible and if not I'm hoping I can do it by including a function on my item renderer that can bridge the gap.

Thanks!

reply

flex3
09/16/2009 - 18:57

if items is changed, and the change is displayed at DataGrid, then I call:

var rowRenderers:Array = dg.listRendererArray;

and want to just change the sytle of first two rows, but row2, 3 are updated ( row1 is never updated).

Do you have any idea why?

Thanks

reply

madanmohan
03/06/2010 - 04:18

hi,
if the datagrid content is changing dynamically, then the listItems arry is not getting modified..

I have a datagrid in that i'll add rows dynamically. so if i want to access the itemRenderer of selected row.. what should i do?

reply

RobC
03/09/2010 - 15:34

Hi, i have the next problem, perhaps you could help me. Im basically getting a timestamp from amfphp, wich i want to use in a datefield item renderer.

The problem is that i always get an error. Aparently it wont cast the string/number sent by amfphp into a date.

However if i do Date(amfphpResult) it will work. So i dont know how to cast it before sending it to the datagrid.

reply

shaning
03/12/2010 - 09:53

Excellent post. Based you your work, I created a function to retrieve the cell values of DataGrid. See my post at:
http://resources.esri.com/arcgisserver/apis/flex/index.cfm?fa=codeGalleryDetails&scriptID=16863

reply

john mish
06/19/2010 - 01:40

I have also used this with custom itemRender's to do cool stuff like enable/disable buttons in DataGrid columns, switch images, etc.
club penguin cheats

reply

Sebastian
07/29/2010 - 11:25

Hi,

I need a similar function but I return sludge from the datagrid itemRenderer that are not only visible

thanks

reply

The Fattest
07/29/2010 - 14:34

not sure i know what you mean. in a datagrid there are only slightly more itemrenderers than what is visible because it reuses them.

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors