Search code examples
apache-flexactionscriptitemrendereradvanceddatagrid

Itemrenderer crash when selected


have an advanced datagrid with a simple custom mxadvanceddatagriditemrenderer. I want the renderer to only display an image when the row is hovered or selected. Right now I am doing that by using the excludeFrom="normal" tag on my image.

It works fine (minus the selected state, it disappears when selected) when I have the states hovered and normal defined. When I try to define a selected state, upon row click I get the following error:

RangeError: Index 0 is out of range.
    at spark.components::Group/checkForRangeError()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1106]
    at spark.components::Group/setElementIndex()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1265]
    at spark.components::Group/addElementAt()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1167]
    at mx.states::AddItems/addItemsToContentHolder()[E:\dev\4.x\frameworks\projects\framework\src\mx\states\AddItems.as:737]
    at mx.states::AddItems/apply()[E:\dev\4.x\frameworks\projects\framework\src\mx\states\AddItems.as:545]
[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:9961] ... etc

Has anyone experienced this before or know a solution?

Thanks

EDIT: the code involved is very simple:

<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" focusEnabled="false">
<fx:Script>
<![CDATA[
import mx.collections.IList;
protected function removeRow(event:MouseEvent):void
{
var ind :int = IList(parentDocument.dataGrid.dataProvider).getItemIndex(data);
IList(parentDocument.dataGrid.dataProvider).removeItemAt(ind);
}   
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="hovered"/>
<s:State name="selected"/>
</s:states>
<mx:Image id="removeButton" excludeFrom="normal" source="@Embed(source='../assets/icons/close_icon.gif')" click="removeRow(event)" width="10" height="10" alpha=".5" toolTip="{resourceManager.getString('localization', 'REMOVE')}"/>
</s:MXAdvancedDataGridItemRenderer>

Solution

  • It would seem - though admiddetly it's a bit of a guess - that you're trying to remove the itemrenderer while changing its state (to 'selected' by clicking on it) at the same time.

    Here's my solution for the kind of situation where you want to remove an itemrenderer by clicking on it: just make it dispatch a bubbling "remove" event and let some kind of controller handle the removal.

    So your itemrender might look like this:

    <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                    xmlns:s="library://ns.adobe.com/flex/spark">
    
        <fx:Script>
            <![CDATA[
                import mx.events.FlexEvent;
            ]]>
        </fx:Script>
    
        <s:states>
            <s:State name="normal" />
            <s:State name="hovered" />
            <s:State name="selected" />
        </s:states>
    
        <!-- some other stuff -->
    
        <s:Button label="remove me" excludeFrom="normal"
                  click="dispatchEvent(new FlexEvent(FlexEvent.REMOVE, true))" />
    
    </s:ItemRenderer>
    

    The 'true' value there is important to make the event bubble all the way down to the List component.

    Then in a controller that has a reference to the List (or DataGrid) or perhaps in a subclass of List (or DataGrid), you trap that event and remove the item.

    theList.addEventListener(FlexEvent.REMOVE, handleRemoveRequest);
    
    private function handleRemoveRequest(event:FlexEvent):void {
        var itemRender:IItemRenderer = event.target as IITemrenderer;
        var item:SomeClass = itemRender.data;
        var index:int = theDataProvider.getItemIndex(item);
        theDataProvider.removeItemAt(index);
    }
    

    Here it's important that you use target instead of currentTarget because the former will be the ItemRenderer and the latter will be the List itself.