views:

1553

answers:

3

Hello.

I have a source collection (now a simple Array). At run-time I create ArrayCollections using the same array as the source (each collection show the same source, but they are differently filtered). My problem is, when a new item added to the source, the already created arraycollections wont updated if one of the property of this new item is updated.

Anyone has a solution to this? What if my source is a Dictionary. How to create different ArrayCollections from the source dictionary, while the collections update whenever new item added, or an item is updated?

thanx

A: 

I believe you will need to use ObjectUtil.copy() and make copies of your Array.

James Ward
+1  A: 

The issue is that arrays aren't [Bindable] in Flex. So you have a few options:

  • Make source an ArrayCollection, and addEventListener for CollectionEvent.COLLECTION_CHANGE.
  • Add items to all array collections in some method addItemToCollections to keep them all in sync.

Here is an example of what I am describing:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:local="*"
    creationComplete="creationCompleteHandler()">

    <mx:Script>
        <![CDATA[
            import mx.events.CollectionEvent;
            import mx.events.CollectionEventKind;
            import mx.collections.ArrayCollection;
            import ColorPalette;

            protected function creationCompleteHandler():void
            {
                var item:Object;
                var i:int = 0;
                var n:int = source.length;
                for (i; i < n; i++)
                {
                    item = source[i];
                    collectionA.addItem(item);
                    collectionB.addItem(item);
                    collectionC.addItem(item);
                    bindableCollection.addItem(item);
                }
                bindableCollection.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler);
            }

            protected function collectionChangeHandler(event:CollectionEvent):void
            {
                switch (event.kind)
                {
                    case CollectionEventKind.ADD :
                        collectionA.addItem(event.items[0]);
                        collectionB.addItem(event.items[0]);
                        collectionC.addItem(event.items[0]);
                    break;
                }
            }

            public function addItem():void
            {
                source.push({name:"new item " + (Math.random()*1000).toString()});
            }

            public function addItemToCollection():void
            {
                var item:Object = {name:"new item " + (Math.round(Math.random()*1000)).toString()};
                collectionA.addItem(item);
                collectionB.addItem(item);
                collectionC.addItem(item);
            }

            public function addToBindableCollection():void
            {
                var item:Object = {name:"new item " + (Math.round(Math.random()*1000)).toString()};
                bindableCollection.addItem(item);
            }

        ]]>
    </mx:Script>

    <mx:Array id="source">
        <mx:Object name="one"/>
        <mx:Object name="two"/>
        <mx:Object name="three"/>
    </mx:Array>

    <mx:ArrayCollection id="collectionA"/>
    <mx:ArrayCollection id="collectionB"/>
    <mx:ArrayCollection id="collectionC"/>
    <mx:ArrayCollection id="bindableCollection"/>

    <!-- sample lists -->
    <mx:Panel id="panel" width="100%" height="100%">
        <mx:Button label="Add Item to Source" click="addItem()"/>
        <mx:Button label="Add Item to Collections" click="addItemToCollection()"/>
        <mx:Button label="Add Item to Bindable Collection" click="addToBindableCollection()"/>
        <mx:HBox width="100%" height="100%">
            <mx:List id="listA" dataProvider="{collectionA}" labelField="name"/>
            <mx:List id="listB" dataProvider="{collectionB}" labelField="name"/>
            <mx:List id="listC" dataProvider="{collectionC}" labelField="name"/>
        </mx:HBox>
    </mx:Panel>

</mx:Application>

Let me know if that helps, Lance

viatropos
Hello!I am at a computer, where is no flex, I can check this code tomorrow.But,IT is clear, that addItem make the collection to listen to items propertyChange event. The problem with this solution is ,that i have to track the collectionX collections. But i want to dynamically create them, and use the new collectionX in a dataprovider, and automatically garbage collect those arrays, which are not used anywhere as dataproviders.A workaround could be to point to collectionXes with weakreferences?Or to listen to the component removed event, when assigning collectionX to it as dataprovider?
thanx for helping, see my simple solution, and tell me what you think.
A: 

My solution is: Ive created a new class derived from ArrayCollection. Name it SourceCollection. Added a new private member that is a Dictionary, created with weakKeys turned to true. A new public function creates a new ArrayCollection from its elements, and add the reference of this created collection to the private dictionary like:

public function createCollection():ArrayCollection
{
   var result:ArrayCollection = new ArrayCollection();
       result.addAll(this);
   createdCollections[result] = null;
   return result;
}

Overrided the addItemAt, removeItemAt and removeAll function: each calls its super function and iterates through the dictionary, and do the appropriate function. Note addItem and addAll also calls addItemAt, so dont need to override them. One example is:

override public function addItemAt(item:Object, index:int):void
{
   super.addItemAt(item, index);

   for (var coll:Object in createdCollections)
   {
     (coll as ArrayCollection).addItemAt(item, index);
   }
}

Also added a test function that iterates through the dictionary, and count the items. If i dynamically creates Lists and assign ArrayCollection created from source with createCollection function, adding, removeing reflected fine, all has the same source items, that i wanted, and after removing dynamically created lists, after a while, tracked list count decreases automatically.

If you put objects in the source that dispatches propertyChange event on any change, all Lists shows the change, too.