AdobeStock_455007340

Using ActionScript To Create Reusable Flex Renderers

Item renderers are the key to customizing just about any Flex controls. If you want numbers in a data grid column to be green or red (based on whether they are positive or negative), you use a cell renderer. If you want list items to be displayed on multiple lines with data from multiple fields combined in a single display, you use a renderer. If you are using TileList to display data, then again you use a renderer to actually define the display.
Renderers can be written in MXML or ActionScript, and here is one reason why you may want to opt for the latter.
The following is a simple DataGrid example. An array contains five objects, each with three values, and then the results are displayed in a DataGrid.








Now what if you wanted the numbers right aligned and formatted using thousands separators? That’s a job for a custom renderer, and here is an MXML example that would do the trick:





To use this renderer you’d just change the DataGridColumn, like this (assuming the renderer was named MyRenderer.mxml):

But what if you wanted to then reuse the renderer for both of the numeric columns? The renderer receives an object named data that contains the object to be displayed, and has to specify the column to be displayed, hard coded (in this case data.q1). As such, you would need another renderer, just like the first, but with a different column specified.
To get around this problem you could implement IDropInListItemRenderer so as to obtain column info, but there is a cleaner option. Here is the ActionScript renderer:
package {
import mx.controls.Label;
import mx.formatters.NumberFormatter;
public class MyRenderer extends Label
{
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
setStyle("textAlign", "right");
var nf:NumberFormatter = new NumberFormatter();
nf.useThousandsSeparator=true;
this.text=nf.format(this.text);
}
}
}

This version accomplishes the same result, but is not column specific, and can thus be used in multiple DataGrid columns, as seen here (assuming the file is named MyRenderer.as):

13 responses to “Using ActionScript To Create Reusable Flex Renderers”

  1. Lokesh Avatar
    Lokesh

    Thanks for the little how-to on item renders. It helped!

  2. AndyC Avatar
    AndyC

    This works fine if I call the package MyRenderer.as and put it in the same folder as the reusableRenderer.mxml file
    However I’d like to have a seperate subfolder for this type of formatting e.g Examples/myFormatters/MyRenderer.as
    Do I need to name the package and how would I refer to it in the mxml file Examples/reusableRenderer.mxml
    I’m having a bit of trouble sorting this out
    Cheers

  3. AndrewW Avatar
    AndrewW

    You should probably override the text setter instead of updateDisplayList:
    private formatter:NumberFormatter;
    public function MyRenderer() {
    super();
    formatter = new NumberFormatter();
    formatter.useThousandsSeparator=true;
    }
    public override function set text(value:String):void {
    super.text(formatter.format(value));
    }

  4. Subba Avatar
    Subba

    Hi ben,
    I have a DataGrid with 10 columns and 5 rows.Now i want to access each row in that column(column name=name) i.e access each each name and give different color for each name.Now when i use text="{data.name}", it is selecting same color for all names.Is there a way I can access each element(cell) and give different colors?
    MyRenderer.mxml
    <mx:Label textAlign="right" text="{data.name}" alpha="0.1" color="#ff0033" width="100%" />

  5. James Ward Avatar
    James Ward

    AndyC,
    Yes, you will have to specify a package name, like:
    package Examples.myFormatters
    {
    Also, change the itemRenderer property to "Examples.myFormatters.MyRenderer".
    Hope that helps.
    -James

  6. chris Avatar
    chris

    I’ve a problem with an itemRenderer:
    <mx:DataGridColumn dataField="col6" headerText="Column #6">
    <mx:itemRenderer>
    <mx:Component>
    <mx:HBox width="100%" horizontalAlign="center"
    creationComplete="initRenderer();">
    <mx:Script>
    <![CDATA[
    private function initRenderer() : void
    {
    /**
    * Can I here get the access to the
    * current dataField of this column?
    * Yes, I can get here the value of
    * this column by using data.col6,
    * but I need to write universal
    * component. The problem is that
    * I can’t get access to the listData
    * because component based on container: HBox
    */
    }
    ]]>
    </mx:Script>
    </mx:HBox>
    </mx:Component>
    </mx:itemRenderer>
    </mx:DataGridColumn>
    Please, give me any advice.
    Thanks,
    Chris Lee

  7. James Ward Avatar
    James Ward

    You should also be able to access the listData object which should give you what you need.

  8. Chris R. Avatar
    Chris R.

    I’ve a problem with an DropInItemRender for images which is dependend to a change event. That means i have to set the itemRenderer property dynamically from a function in ActionScript, eg:
    dg.columns[i].itemRenderer = "mx.controls.Image";
    But this throws an Error #1034 Type coercion "mx.controls.Image" could not be transformed to mx.core.IFactory.
    Any Ideas?
    Thanks in Advance

  9. James Ward Avatar
    James Ward

    I think you need to use the ClassFactory utility class:
    http://livedocs.macromedia.com/flex/2/langref/mx/core/ClassFactory.html

  10. Chris R. Avatar
    Chris R.

    Thanks,
    this works!!!

  11. Leonardo Sobral Avatar
    Leonardo Sobral

    When you add more rows to the grid and scroll, values on cells go crazy… Is that a bug?

  12. Scott Avatar
    Scott

    This is wonderful for numberFormatters, but I can’t seem to get it to render properly with a CurrencyFormatter. For some reason, it drops the "negative sign" out:
    var cf:CurrencyFormatter = new CurrencyFormatter();
    cf.useNegativeSign=true;
    cf.useThousandsSeparator=true;
    cf.precision=2;
    cf.currencySymbol="$";
    this.text=cf.format(this.text);
    Am I missing something here?

  13. none Avatar
    none

    fyi: i realize this is an old post, but it doesn’t work when you have multiple columns and you sort.
    in short, reading the state of the cell "this.text" is not reliable (or so it seems) when sorting.
    probably best to just remote this example. thx.

Leave a Reply