Search code examples
apache-flexrefreshinternalarraycollectionlistcollectionview

Flex applying the sort/filter on an arraycollection without dispatching event


I have a object that is extended from arraycollection. This object has to access and manipulate the arraycollections source object. When this happens, the local sorted/filter copy of data goes out of sync with the source data. To line things up correctly, the sort/filter needs to be re-applied.

To do this normally, you would call refresh() on the arraycollection, but this also broadcasts a refresh event. What I want is to update the sort/filter without dispatching an event.

Having looked into the ArrayCollection class, I can see it is extended from ListCollectionView. The refresh function

public function refresh():Boolean
{
    return internalRefresh(true);
}

is in ListCollectionView and it calls this function

private function internalRefresh(dispatch:Boolean):Boolean
{
    if (sort || filterFunction != null)
    {
        try
        {
            populateLocalIndex();
        }
        catch(pending:ItemPendingError)
        {
            pending.addResponder(new ItemResponder(
                function(data:Object, token:Object = null):void
                {
                    internalRefresh(dispatch);
                },
                function(info:Object, token:Object = null):void
                {
                    //no-op
                }));
            return false;
        }

        if (filterFunction != null)
        {
            var tmp:Array = [];
            var len:int = localIndex.length;
            for (var i:int = 0; i < len; i++)
            {
                var item:Object = localIndex[i];
                if (filterFunction(item))
                {
                    tmp.push(item);
                }
            }
            localIndex = tmp;
        }
        if (sort)
        {
            sort.sort(localIndex);
            dispatch = true;
        }
    }
    else if (localIndex)
    {
        localIndex = null;
    }

    revision++;
    pendingUpdates = null;
    if (dispatch)
    {
        var refreshEvent:CollectionEvent =
            new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
        refreshEvent.kind = CollectionEventKind.REFRESH;
        dispatchEvent(refreshEvent);
    }
    return true;
}

annoyingly, that function is private and so is unavailable to and class that extends ListCollectionView. Also, a lot of what is in the internalRefresh function is private too.

Does anyone know of a way to call internalRefresh from a class that extends ArrayCollection? Or a way of stopping the refresh event from being dispatched when refresh is called?


Solution

  • My (read:hack) solution to this:

    addEventListener(CollectionEventKind.REFRESH, handlerHack, true);
    

    The true adds this listener onCapture, before anyone else gets to act on the event.

    Before you call the collection.refresh() to update sort/filter, set a boolean flag to true.

    discardRefreshEvent = true;
    myCol.refresh();
    

    In the listener...

    private function handlerHack(evt:CollectionEvent):void
    {
        if (discardRefreshEvent)
            {
                evt.stopImmediatePropagation();
                discardRefreshEvent = false;
            }
    }
    

    Disclaimer: Haven't done this exact use before (have implemented similar functionality with other events), also only guessing on Event types/names.