Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

The following diagram shows how the ActionScript List component is composed.

Gliffy Diagram
sizeL
nameListComponent

...

The List contains:

  • A selection model which encapsulates a data provider as well knowledge about which item is selected (the item and the index).
  • A view bean bead that displays the container housing the list control.
  • A factory bean bead that can produce instances of item renderers as needed.
  • An item renderer to display each element of the list; created by the factory beanbead.
  • A mouse controller for the list as a whole that handles the selection for the list.
  • A mouse controller for item renderer to handle the hover and selected states.

These parts are specified by the List's style definition in the defaults.css file:

Code Block

List
{
    IBeadModel: ClassReference("org.apache.flex.html.staticControls.beads.models.ArraySelectionModel");
    IBeadView:  ClassReference("org.apache.flex.html.staticControls.beads.ListView");       
    IBeadController: ClassReference("org.apache.flex.html.staticControls.beads.controllers.ListSingleSelectionMouseController");
    IBeadLayout: ClassReference("org.apache.flex.html.staticControls.beads.layouts.NonVirtualVerticalScrollingLayoutVerticalScrollingLayout");
    IDataGroup: ClassReference("org.apache.flex.html.supportClasses.DataGroup");
    IDataProviderItemRendererMapper: ClassReference("org.apache.flex.html.staticControls.beads.TextItemRendererFactoryForArrayDataDataItemRendererFactoryForArrayData");
    IItemRendererClassFactory: ClassReference("org.apache.flex.core.ItemRendererClassFactory");
    IItemRenderer: ClassReference("org.apache.flex.html.staticControls.supportClasses.StringItemRenderer");
}

...

Once the List component and all of the item renderers have been created, the interactive part comes into play. Each item renderer is also a component (strand and beads) and follows the same pattern as other FlexJS components. For the List, the IItemRenderer is specified in defaults.css as the StringItemRenderer class which has its own style definition, show here:

Code Block

StringItemRenderer
{
    IBeadController: ClassReference("org.apache.flex.html.staticControls.beads.controllers.ItemRendererMouseController");
    height: 16;
}

...

In the JavaScript, the bead classes are normal classes and events do not propagate from inner to outer class (the UI in JavaScript are HTML elements that the JavaScript classes are wrapping). This event flow makes it a little challenging to have an event dispatched on an item renderer be detected by the ListSingleSelectionMouseController which is listening for events coming through the view bead. In JavaScript, the event dispatched on the item renderer does not have an event chain parent so that detection is not possible.

Code Block

// from ItemRendererMouseController's handleMouseUp function
this.strand_.get_itemRendererParent().dispatchEvent(newEvent);

Instead, the JavaScript implementation of the List component provides a property, itemRendererParent, to help with the event flow. By dispatching on this property, the same event can reach the ListSingleSelectionMouseController so that the model can be updated in the same way it does in the ActionScript version.

Custom ItemRenderer

This section shows you how to make a custom itemRenderer for a List control.

The first thing to do is map out your data: what does your data look like? For this example, the data is a list of products each having an image of the product, the product's ID, title, and stock status (in stock or out of stock).

The next thing to do is design the itemRender: what do you need to show in each itemRenderer? For this example, the itemRenderer will show an image, a title, and single detail line of text which will be the stock status.

Example ItemRenderer

FlexJS comes with two pre-built itemRenderers and there will probably be more. The TextItemRenderer is used exclusively for arrays of strings and is used with the SimpleList control. The DataItemRenderer is useful for more complex data and that is the class your itemRenderers will mostly extend.

Code Block
public class ProductItemRenderer extends DataItemRenderer
{
    public function ProductItemRenderer()
    {
        super();
    }
		
    private var image:Image;
    private var title:Label;
    private var detail:Label;
}

The example, started above, shows the ProductItemRenderer extending DataItemRenderer and defining the components it needs to display the image, title, and detail elements.

Every itemRenderer should override the addedToParent() function and instantiate the components that make up the itemRenderer, as shown here:

Code Block
    override public function addedToParent():void
    {
        super.addedToParent();

        image = new Image();
        addElement(image);
			
        title = new Label();
        addElement(title);
			
        detail = new Label();
        addElement(detail);
    }

The addedToParent() function is called when the itemRenderer has been instantiated and added to the display list. In the example, the image, title, and detail are created and added to the itemRenderer's display list.

Once an itemRenderer has been created, it will be given the data to show by setting the itemRenderer's data property (virtualized lists, which are not yet developed in FlexJS, will recycle the itemRenderers and set the data property whenever they can used).

Code Block
    override public function set data(value:Object):void
    {
        super.data = value;
			
        image.source = data.image;
        title.text = data.title;
        detail.text = data.detail;
    }

The override of the data property setter should always call super.data = value as the first thing to ensure the data getter returns the correct thing. All this override does it set the appropriate property on the components in the itemRenderer. For example, the title component has its text property set from the data' title property.

Finally, the itemRenderer should respond to changes in its size. The base class, DataItemRenderer, intercepts the events that trigger this and automatically calls its adjustSize() function.

Code Block
    override public function adjustSize():void
    {
        var cy:Number = this.height/2;
			
        image.x = 4;
        image.y = cy - 16;
        image.width = 32;
        image.height = 32;
			
        title.x = 40;
        title.y = cy - 16;
			
        detail.x = 40;
        detail.y = cy;
			
        updateRenderer();
    }

This itemRenderer sample determines the vertical center of its space and then positions the image, title, and detail components from that. Your itemRenderer can do whatever it needs to size and position its component children.

The final step adjustSize() should do is call updateRenderer() which will take care of any background color change in case the itemRenderer is selected or being hovered by the mouse.

While this example does not do it, your itemRenderer may also want to override updateRenderer() and provide different experiences for the hovered and selected states.

Making it Work

Once you have created your itemRenderer you can add it a List control via a style definition (this one appears in the style block of MyInitialView):

Code Block
<fx:Style>
    @namespace basic "library://ns.apache.org/flexjs/basic";
    @namespace sample "products.*";

    sample|ProductItemRenderer {
        height: 40;
        IBeadController: ClassReference("org.apache.flex.html.beads.controllers.ItemRendererMouseController");
    }
</fx:Style>

<basic:List id="productList"  x="20" y="400" width="200" height="150" className="productList">
    <basic:beads>
        <basic:ConstantBinding
                 sourceID="applicationModel"
                 sourcePropertyName="products"
                 destinationPropertyName="dataProvider" />
    </basic:beads>
</basic:List>

The itemRenderer, ProductItemRenderer, is actually in the products package so a @namespace is used to identify it in the style definition. The style definition sets the ProductItemRenderer's height to 40 pixels and makes it use the ItemRendererMouseController to handle the mouse events for roll over, roll out, up, and down which translate to the itemRenderer's hover and selected states.

JavaScript

Note

The example is for ActionScript only. Custom JavaScript itemRenderers are a work in progress.