More Thinking About Item Renderers

Well, the last post definitely got people thinking. Since then I’ve seen a few of you struggle with images, centering, etc. Again, if you’re in a hurry, take a container and center an Image in it, but just be aware that that is kind of heavy.
This example shows how I would do it in order to optimize on performance. Most drop-in renderers like Image and CheckBox are comprised of child components that actually display the content, text and icons. By overriding the updateDisplayList methods, you can center the content without the cost of wrapping the renderer in a container.
Download Source Code
Run Demo
This example also shows how to use labelFunction to map fields in your data to external or embedded images. The usual caveats and disclaimers apply.
-Alex

39 Responses to More Thinking About Item Renderers

  1. Great work man… exactly what I needed….
    check this out I’m using it in the fullScreen mode of a photogallery:
    http://theo.flexcoders.nl/005/

  2. Ben says:

    Hi Alex,
    I am pretty much completely lost in these examples, but I will start with a simple question. How is it that CenteredCheckBox is setting its selected state? How does it know to apply the value of its data property to its selected property?
    Thanks,
    Ben
    ————-
    Ben,
    Sorry you got lost. Maybe what you’re missing is that CheckBox, Image and some other out-of-the-box Flex components are drop-in item renderers. They implement IDropInListItemRenderer and know how to pick up extra information from the DataGrid such as which column they are renderering and therefore which dataField to pick out of the data.
    If you just drop in CheckBox you’ll see it work fine but left-aligned.
    There’s a lot of power in the standard components that can be leveraged once you figure out what they can do. And once you get a better understanding of that, it becomes more clear that lightweight subclassing of these components is better than the old Canvas-with-a-component pattern, which is much easier to learn, but may not be optimal.

  3. Fabian says:

    Hi Alex, great work. I have a dude. If i click in the header for sort, the values of the chekboxes lost, it’s by not have editor ??
    ———-
    Yes, I did not add the code where clicking on the checkbox updates the dataprovider.

  4. Vlad says:

    Hi Alex,
    may be you would be able to advise me. I’m looking for a solution to layout a row such what a line of text would start in the leftmost column and span multiple columns. Content of other columns should be pushed down as to allow space for the text line.
    Thank you in advance,
    Vlad
    ————-
    Haven’t tried this yet, but you will probably need to know that the z order of renderers in a row is left to right where the right side is “above” the left. It turns out that once the list class determines the size and position of the renderer, you can change it later as long as you don’t cause the list to re-render everything. So in your renderers’ updateDisplayList, one should get really wide and the others should move down.
    That’s the theory. I think somebody got this to work. I’d try it myself but I’m pretty busy right now. Good luck
    —————
    Yeah, this is how I’m trying to do it now, but it looks a bit too much as a hack. Well, as long as it works and there is no better way… 🙂
    Cheers,
    Vlad
    —————
    Yeah, we didn’t support row/column span. There should be better support in the next major release.

  5. Hi Alex,
    Thanks for your helpful CenteredWidgets example. I did have some trouble importing it into Flex, but that’s because I am a Flex noobie.
    Anyhow, my question is… I’m trying to make a very simple “Icon + text” combination. Let’s say my icon is 16 pixels square. I’d want perhaps 8 pixels gap. And then the text to the right of the icon.
    I want all this in one column!
    What’s the best way to do this in flex?
    Should I extend your image to draw the text to the right of it? Oh wait, it’s centered isn’t it. I don’t want it centered.
    Thanks if you have any advice.
    —————–
    I would take a UIComponent and add children Image and UITextField. You can look at the Flex framework source for ListItemRenderer for inspiration.

  6. Ashish Mishra says:

    Hi Alex,
    I am trying to display some HTML data to Flex application. From Server it is coming as CDATA. It may contain tables, html text, images things.
    Now I have 2 problems:
    1. Which component is best to display such component. Is there any built in component for this?
    2. I am displaying data in TextArea using its htmlText property. But it is not showing output as it is coming from server. Can u tell me why so?
    Thanks in advance for looking in this problem.
    —————-
    Flash support for HTML is historically poor. Ask about it on FlexCoders and you’ll see alternative approaches, one of which is called HTMLComponent. Oher support may get better over time, but no promises.

  7. Rob Turknett says:

    Hi Alex,
    I would like to create a list item renderer that displays a value as a horizontal bar, as in a bar graph. Do you have any suggestions on how to do this efficiently?
    Thanks!
    Rob
    ——————————-
    I would start with UIComponent and draw a rectangle into its graphics layer. Hope that’s enough info to get you started.

  8. Tony says:

    Alex,
    I just read both of these articles about item renderers. I was really missing the mark. I will fix my grids and let you know how it went.
    What the heck was I thinking. Thank you so much for the redirection. Your rock dude!
    Thanks again,
    Tony

  9. John Lentz says:

    Alex,
    I’m trying to use the CenteredCheckBox in a datagrid, using actionscript instead of mxml. I’ve tried to get the backing arrayCollection to be updated when it changes, but it isn’t working. It reflects the data being sent to the grid, but not the state of the checkboxes. Could you post a quick example of what needs to be added for it to fully function in a datagrid? Thanks, John
    ———–
    How to update depends a bit on the backing data. I implement change event handlers that update the data. You may need to call itemUpdated though

  10. rameen says:

    Alex, I wanted to personally thank you for saving me many painful hours. Thanks a million.
    -Rameen

  11. Nigel says:

    This works but you loose the ability to have a click event in the column which you have with an component.
    Are there other methods of centering the image?
    ————–
    Not sure what you mean by that. You can always put some sort of alpha=0 shield over the entire column if you think you need to detect mouse outside the image bounds.

  12. Alex, these two posts on item renderers have helped me understand what is really going on in the DataGrid so much better than I ever did before. And my grid performance is better now too!
    Thank you very very much for taking the time to help us all out. Most appreciated dude.
    cheers, Adrian

  13. Jonathan says:

    Hi Alex,
    Pretty useful demo here, but I’m having trouble extending it to meet my needs. The images I’m loading are of an unknown variety of heights and widths, and need to be resized to fit the cell if they’re too big. I can get it working for the initial load, but the unpredictability of item renderers messes up the y values after a column re-order or two.
    Keep up the good work
    ————————
    Alex responds:
    Pick a fixed size for the images and scale the actual images to fit. Then it should be more stable

  14. del says:

    alex,
    i was trying to expand on some of the item renderer examples that you gave here, but i ran into some trouble. i am trying to create a renderer that has a clickable image and a text component. i decided to subclass TextInput and add a preceding image but it just doesn’t render properly. when first displayed, the image is positioned at x=-8, y=-8. when the mouseover forces a redraw, the image is properly positioned. also, there appears to be a thin border at the bottom of the cell that i cannot get rid of. any help would be appreciated.
    public class ParameterRenderer extends TextInput
    {
    private var image:Image;
    public function ParameterRenderer()
    {
    super();
    setStyle(“borderStyle”, “none”);
    setStyle(“paddingBottom”, 0);
    }
    override public function validateNow():void
    {
    // see BackgroundColorRenderer
    }
    override protected function updateDisplayList(w:Number, h:Number):void {
    super.updateDisplayList(w, h);
    // lifted from CenteredImage
    if (image.content) {
    var contentHolder:Loader = image.content.parent as Loader;
    contentHolder.width = contentHolder.contentLoaderInfo.width;
    contentHolder.height = contentHolder.contentLoaderInfo.height;
    contentHolder.x = textField.x;
    contentHolder.y = (h – contentHolder.contentLoaderInfo.height) / 2;
    }
    }
    override protected function createChildren():void {
    super.createChildren();
    textField.selectable = false;
    if (!image) {
    image = new Image();
    // attempt to get image to position properly
    image.width = 16;
    image.height = 16;
    image.source = “../img/delete2.gif”;
    addChild(DisplayObject(image));
    image.addEventListener(MouseEvent.CLICK, delete_onClick);
    invalidateDisplayList();
    image.move(2,0);
    }
    }
    override protected function createBorder():void {
    // thought this might get rid of bottom border
    }
    public function delete_onClick(event:MouseEvent):void {
    // do something
    }
    ——————-
    Alex responds:
    ListItemRenderer has an icon and a TextField which could be editable. Might be easier to start there.

  15. Chad says:

    Hi Alex,
    Thanks for these great demos. I was really struggling with itemRenderers until I found these articles.
    I have a question about the centered checkbox example… My datasource is returning 0/1 for boolean data, rather than true/false, and I can’t get the checkboxes to show selected. I tried adding a labelFunction that returns true if 1 and false if 0, but that doesn’t seem to work either (even if I only return true from my labelFunction, they’re all unchecked).
    I feel like a total newb asking, but what am I missing?
    Thanks
    ————————
    Alex responds:
    The checkbox just pulls the field. It won’t listen to labelFunction. You could wrap data objects or override the data setter on checkbox.

  16. Nick Cherry says:

    Hi Alex,
    A nice blog you’ve got going – bookmarked for later use, as I’m sure it will come up.
    I have a really simple question… I’m trying to use custom renderers to format the text of each column’s header individually – nothing fancy like checkboxes or comboboxes…just text. Might someone be able to tell me what I’m doing wrong here?
    import fl.controls.dataGridClasses.HeaderRenderer;
    import flash.text.TextFormat;
    public class MyHeaderRenderer extends HeaderRenderer {
    var myTextFormat:TextFormat = new TextFormat();
    myTextFormat.bold = true;
    myTextFormat.align = “center”;
    setStyle(“headerTextFormat”, myTextFormat);
    //setStyle(“textFormat”, myTextFormat);
    }
    …and then:
    myDataGrid.getColumnAt(0).headerRenderer = MyHeaderRenderer;
    ——————-
    Alex responds:
    TextFormat is a low-level Flash thing that formats Text. The Flex style system doesn’t use it until the very end and will overwrite any TextFormat you do apply.
    Use CSS styles like fontWeight and textAlign insttead

  17. Alex C says:

    I’m trying to reference a TextInput control inside an itemRenderer when a Button is clicked from within that same renderer. I’m able to change the text of the TextInput, but when I scroll down, I see that other rows (at random) have that same new value in their TextInput boxes. What am I doing wrong? Any workaround? Help!!!!
    ———————-
    Alex responds:
    Classic symptoms of recycling. The contents of the TextInput need to be derived from the .data property

  18. mitesh says:

    Hi,
    I have a problem using a custom ItemRenderer for a Horizontallist control. I require to use two comboboxes (wrapped in a canvas) to render Hlist control. That is, for each valuepair in HList will be rendered (and edited) by this custom component featuring two comboboxes. My problem is that I can’t even figure out how to do it with a single combobox (wrapped in a canvas). I have successfully implemented the combobox itemrenderers in datagrid, but with HList, I don’t know how to use getter/setter methods to pass data from HList to the rendered control.
    Can you help me out? If I can get it work with a single combobox (wrapped in a canvas), I may manage to do the rest.
    Thanks,
    Mits
    ————————
    Alex responds:
    I’d ask on FlexCoders. It really depends on what your data looks like

  19. Rafael says:

    Hi Alex,
    I want to use buttons with multiple lines inside of a tileList, have you any example of that?
    Thanks in advance.
    Rafael
    ———————-
    Alex responds:
    Did you try using my multiline button example in a tile list?
    http://blogs.adobe.com/aharui/2007/04/multiline_buttons.html

  20. Amanda says:

    Hi Alex,
    Very interesting article. Thank you for posting it. I have a much more complex need at this moment, which had me searching all through google and landed me (thankfully) here.
    I would like to create a runtime itemRenderer. Basically, I have a DataGrid. This datagrid of course is fed in information in the form of an arrayCollection to display what has already been saved, as well as gives the option to add a new line item.
    I would like to have a column completely driven by a drop-down selection in column one.
    Example – column one has a combobox with three choices: gold, silver, other.
    Column two would generate a combo box and populate it with choices of gold jewelry for choice1, or choices of silver jewelry for choice 2.
    If the user selects other, a TextInput is rendered instead for manual entry.
    I have tried so many things to get this to work, but am having so many issues. Mostly around getting data populated and saved, but also in some of the renderings as well.
    Any suggestions?
    Thanks,
    Amanda
    ————————
    Alex responds:
    Should be possible. Remember to keep things data-driven. The second column’s dataprovider should be based on the first column’s data.
    You may need a custom renderer that can either be a combobox or textinput.
    I’d ask for help on FlexCoders. Some folks have solved parts of this problem before.

  21. Amanda says:

    Oh, and I forgot to mention that I am using Flex 2.
    Thanks Alex!
    —————————
    Alex responds:
    Then you’ll probably have to use a custom renderer that switches its child from being a ComboBox or TextInput.
    In Flex 3 some new APIs were added to data-drive which renderer is created.

  22. Raymond says:

    Alex,
    I am going over your posts and was wondering if it is possible to combine a few of them into one sample. i.e. Let’s say you have a datagrid whose dataprovider is an ArrayCollection provided to you by an outside method on the server. Then you want to do the following in one grid:
    1. Ability to have EVERY header of the datagrid columns be a combo box. This is like your one example but by having each header with the same capability you get a real drill down capability.
    2. The ability to render a complete row a color of red or yellow based on the word in one of the columns. i.e. You have a column say cable outage and if the row has the term scheduled outage you color that entire row red and it thus turns back to normal color when the term changes from scheduled to say none.
    3. The ability to click one column’s cell and have it pop-up a window with a checklist of three items. You select one of the three and it updates that cell.
    4. The ability to take one entire column which contains time in Epoch value and display it as regular time.
    Would the best way to do this be to create one component and extrapolate each concept as a specific render class. Also I am a simple guy trying to come up with a cool way to extend my internal tool at work. How long should it take to slap something like this together? I am attempting it on my own but we really really need this fast and I am not as strong a coder in flex as you are yet. Let me know. Thanks for all the tips and demo’s you have made so far.
    ————————–
    Alex responds:
    I wish I could create examples for everything, but I don’t have the time. It’s hard to estimate how long it will take you. I would ask questions on FlexCoders. You’ll get faster responses there.

  23. Fred Allen says:

    Alex, I appreciate your column. I am a new Flex developer and would like to know how to reset a combobox item renderer in a datagrid column. I understand that item renderers are reused and I am seeing that. I have a combobox itemrenderer for a cell in a data grid. After I have added a couple of rows and selected an item from the dropdown list, if I delete a row or two then add another row I see the selection from a previous row in the combobox. I also understand that I need to reinitialize the item renderer so that it appears blank on the new row but I don’t know how. Your help will be greatly appreciated. Thanks very much.
    ———————-
    Alex responds:
    Everything in a renderer should be data-driven (derived from the data property). The ComboBox will by default set its selection to the text of the item if it can find it in the ComboBox’s dataProvider.
    If you need further assistance, you’ll get faster response posting to FlexCoders or the Adobe forums.

  24. gina says:

    Hi there!,
    I have problem with my tilelist. I want to view the data in tilelist in random order. The data are form xml list. How can i view data in random order? . Please send reply to my email.Thanks!
    -gina
    ———————
    Alex responds:
    Sorry, I cannot help you directly via email. Please post your question to one of the forums. Other folks will have a chance to help you as well.

  25. vin says:

    Hi Alex,
    I got two questions regarding Itemrenderers.
    1) I have used your centered CheckBox but if a user changes the state of checkbox it is not updating the collection.
    2) Similarly I have used radiobutton as item renderer in one column and assigned them to a RadioButton Group so that the user can only select one row at a time. problem here is I want to preselect one radio button during initialization. can you hlp me how to do that .
    I was struggling really hard with these two issues.Any help would be appreciated
    thanks in advance
    vin
    —————————
    Alex responds:
    I think you might find the Checkbox and DataGrid posts helpful for both those problems. You can swap in the centered checkbox for the regular checkbox

  26. christian smith says:

    that was great! What I really need is an example using a renderer on how to change the cell types for a column at runtime based on the data field value.
    For instance, if a value reading into the dataField is “requested” I would want to display “requested” as a linkbar in the cell, however if the value is “pending” I want “pending” to display as a button. How can I do this?

  27. Alex Harui says:

    If you don’t have lots of cells, you can use states. If you have lots of cells, use actionscript. Either way, you check the data object and decide whether to instantiate a link button or a regular button and add it as a child or change their visibility.

  28. mk says:

    Hi Alex
    I am struggling with itemrendering in datagird
    I have a checkbox in the datagrid.Dataprovider for the datagird is returned from service the xml wont be having the data for checkbox.I need to find the which row is selected in the datagrid and the selected row details to be displayed.i am the beginner..could u please help me in this issue

  29. Alex Harui says:

    You’ll get faster help asking on the Adobe forums for Flex.

  30. jenue says:

    how about the checkbox will automatically checked based on values from dataprovider? how to do that?

  31. Alex Harui says:

    There is a checkbox datagrid example on this blog.

  32. Gamini says:

    I added a itemRenderer to a Grid column, now multicolumn sort does not work, if column with itemRenderr is selected first. I didn’t see multi-column sort in any of the examples given here.How would I implement that? Thanks.

  33. Gamini says:

    When you try to sort a column with an itemRenderer (in *.mxml file with HBox), the little arrow symbol does not appear in the column header.

  34. Alex Harui says:

    I would probably have custom header renderers that show the UI you want and some properties to track the last columns sorted.

  35. Alex Harui says:

    Are you using the default header renderer? A custom header renderer has to allow itself to be shrunk in order to make room for the sort arrow

  36. Prakash says:

    Hi,
    I have a strange problem in datagrid control. In my example, i have two columns in a datagrid. first column display a text and second column displays a formatted output of custom itemrenderer. while loading data it is displaying properly. if i scroll down and up to see the next rows in the grid, it is not displaying data as it is. the data in the first row is shown in 5th row and 8th row data in 2nd row like rows are jumbling.
    Any idea about this problem?
    Thanks and Regards,
    Prakash.

  37. Alex Harui says:

    That is a classic recycling problem. Make sure the renderer determines all of its visuals from the data object or associated data.

  38. Coven says:

    i want to change background color of specific rows of datagrid at run time on button click, do you know how to make it?