8 Replies Latest reply on Jan 8, 2008 10:05 PM by dazweeja

    Mapping Between ArrayCollection and its source

    Mirza Asim Level 1
      Is there any way to map an index of ArrayCollection's item to its source's corresponding item?
        • 1. Re: Mapping Between ArrayCollection and its source
          m_hartnett Level 3
          Can you give an example of what you are trying to do?
          • 2. Re: Mapping Between ArrayCollection and its source
            Mirza Asim Level 1
            Actually, I am using ArrayCollection as the dataProvider of AdvancedDataGrid. When I apply filter on ArrayCollection then some of the items from the collection are filtered out and the indices of the remaining ones get changed. I want to keep track the original indices as well.
            One way that I found out is to get the item from the collection and search it in its source. Is there any other way to solve this problem?
            • 3. Re: Mapping Between ArrayCollection and its source
              dazweeja
              You can access the underlying array of an ArrayCollection through its 'source' property so you could try something like this to create an unfiltered ArrayCollection:

              // filtered ArrayCollection is named filteredAC
              var newAC:ArrayCollection = new ArrayCollection(filteredAC.source);

              Or maybe just create a new ArrayCollection from the original array. I don't think there's anything stopping you from having multiple AC's with the same source array (but I could be wrong).

              You can also make a copy of the AC (unfiltered) using:

              var newAC:ArrayCollection = new ArrayCollection(filteredAC.source.slice());

              Also for searching in AC's, I often find it useful to createCursor() and then use the findAny, findFirst and findLast functions.

              Cheers,
              Darren.


              • 4. Re: Mapping Between ArrayCollection and its source
                Mirza Asim Level 1
                Thanks Mr. Darren.
                But I think I did not convey my query correctly. So, let me rephrase it a little bit.

                Does ArrayCollection keep track such a mapping (by default) or we have to do something by our own, like Mr. Darren did?
                • 5. Re: Mapping Between ArrayCollection and its source
                  dazweeja Level 1
                  I think I know what you mean. I don't think that Flex has this mapping that you can access. The way I get around this is to use getItemIndex (even on a filtered list). For example if you wanted to update the selectedItem of a DataGrid, you could:

                  private function updateAC():void
                  {
                  // get selected item
                  var thisItem:Object = myDataGrid.selectedItem;
                  // get index before changes are made to object
                  var thisIndex:int = myCollection.getItemIndex(thisItem);
                  // make your changes here, eg. maybe you want to change the 'name' field in the array
                  thisItem.first = nameField.text;
                  // update the AC using setItemAt so that dataGrid is notified of AC change
                  myCollection.setItemAt(thisItem, thisIndex);
                  }

                  or this:

                  private function updateAC2():void
                  {
                  var oldItem:Object = myDataGrid.selectedItem;
                  // make a copy and alter that
                  var newItem:Object = ObjectUtil.copy(oldItem);
                  // make a change, eg. maybe you want to change the 'name' field in the array
                  newItem.first = nameField.text;
                  // update the AC
                  myCollection.setItemAt(newItem, myCollection.getItemIndex(oldItem));
                  }

                  Maybe there's an easier way to do this. If so, I'd be interested in hearing about it too.

                  Cheers,
                  Darren.
                  • 6. Re: Mapping Between ArrayCollection and its source
                    m_hartnett Level 3
                    As darren says, use the source of the array collection to get to the unfiltered data. Here is a small example. One ComboBox uses the AC as the dataProvider while the other ComboBox uses the AC.source as the dataProvider.

                    Before the filter button is hit you can see that both lists are the same after filtering you can see that only the first box filtered and the second box is the original list.


                    <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml"
                    creationComplete="createComplete()"
                    layout="absolute">

                    <mx:Script>
                    <![CDATA[
                    import mx.collections.ArrayCollection;

                    [Bindable]
                    private var dsAC : ArrayCollection = new ArrayCollection();

                    private function createComplete() {
                    dsAC.addItem("Apple");
                    dsAC.addItem("Banana");
                    dsAC.addItem("Grape");
                    dsAC.addItem("Orange");
                    dsAC.addItem("Barley");
                    dsAC.addItem("Corn");
                    }


                    [Bindable]
                    public var selectedItem:Object;

                    private function filterData(e:Event): void {

                    dsAC.filterFunction=stateFilterFunc;
                    //Refresh the collection view to apply the filter.
                    dsAC.refresh();


                    var obj : Object = cb.listData;
                    var j : String = "";
                    }

                    public function stateFilterFunc(item:Object):Boolean {
                    return item >= "B" && item < "G";
                    }



                    ]]>
                    </mx:Script>
                    <mx:ComboBox id="cb0" dataProvider="{dsAC}" width="150"
                    close="selectedItem=ComboBox(event.target).selectedItem" x="103" y="6"/>
                    <mx:ComboBox id="cb" dataProvider="{dsAC.source}" width="150"
                    close="selectedItem=ComboBox(event.target).selectedItem" x="105" y="92"/>
                    <mx:Button label="Filter" click="filterData(event)" x="199" y="167"/>
                    <mx:Label x="24" y="8" text="Filtered Box"/>
                    <mx:Label x="24" y="72"/>
                    <mx:Text x="13" y="56" text="Box whose dataprovider is the AC.source" width="82"/>
                    </mx:Application>
                    • 7. Re: Mapping Between ArrayCollection and its source
                      Mirza Asim Level 1
                      Darren and mhartnett, Thanks for your support to solve this problem. I came up with a solution. And I need your comments on this.

                      I am gonna add a dummy column (of unique values) in the source of ArrayCollection. This column will be hidden in the Visual Component (like datagrid). By using this column I can map the items between ArrayCollection and its source.
                      I think its efficient not only in time domain but also in space domain.

                      What you think?
                      • 8. Re: Mapping Between ArrayCollection and its source
                        dazweeja Level 1
                        Are you talking about adding an ID field to the Array? Sounds fine. Then you can find a specific item in the AC with something like:

                        var myCollection:ArrayCollection = new ArrayCollection(mySourceArray);
                        var myCursor:IViewCursor = myCollection.createCursor();
                        if(myCursor.findAny({id: someValue})) {
                        var someItem:Object = myCursor.current; // found it!
                        }

                        Cheers,
                        Darren.