tags:

views:

865

answers:

2

It seems that ComboBoxes loose their selected item after their dataProvider updates, even if the same selected item is still in the dataProvider. They convert back to the first item being selected. Is there anyway to prevent this? So that if the same object is in the dataProvider it keeps the same object selected and only reverts back to the first index if the selected object is not in the updated dataProvider?

Thanks!

A: 

Well I was able to extend the ComboBox with this class, which just looks for the selected label and compares with labels from the new dataProvider. It seems to work, although kinda ad-hoc. I was hoping for a scalable solution.

package
{
    import mx.controls.ComboBox;
    import mx.collections.ArrayCollection;

    public class SelectionKeepingComboBox extends ComboBox
    {
     public function SelectionKeepingComboBox()
     {
      super();
     }

     override public function set dataProvider(value:Object):void
     {
      var curSelectedLabel:String;
      if(this.selectedItem)
      {
        curSelectedLabel = this.selectedLabel;
      }

      super.dataProvider = value;

      if(curSelectedLabel == null)
      {
        return;
      }

      var dp:Array;
      if(this.dataProvider is ArrayCollection)
      {
       dp = this.dataProvider.toArray();
      }
      else
      {
       dp = this.dataProvider as Array;
      }
      for(var i:uint = 0; i<dp.length; i++)
      {
       var obj:Object = dp[i];
       var dpLabel:String = obj.label;
       if(dpLabel == curSelectedLabel)
       {
        this.selectedItem = obj;
       } 
      }
     }

    }
}
John Isaacks
+1  A: 

If the ComboBox looses its selected item, it means the dataProvider isn't updated - it is replaced. If you bind a ComboBox to an ArrayCollection and then add an item to the AC, The ComboBox is updated without loosing its selectedItem.

Sometimes you have to replace the dataProvider and in those cases, you have to listen for the updateComplete-event and reset the selectedItem. You can try this code:

<mx:Script>
 <![CDATA[
  import mx.controls.ComboBox;
  import mx.events.ListEvent;
  import mx.events.FlexEvent;
  import mx.collections.ArrayCollection;

  [Bindable]
  private var dp:ArrayCollection = new ArrayCollection(["Item 1", "Item 2", "Item 3"]);

  private var selectedItem:*;
  private var dataProvider:*;

  private function onChange(event:ListEvent):void {
   selectedItem = (event.currentTarget as ComboBox).selectedItem;
  }
  private function onUpdateComplete(event:FlexEvent):void {
   trace(event);
   var cb:ComboBox = event.currentTarget as ComboBox;
   if(dataProvider == null || cb.dataProvider != dataProvider) {
    if(selectedItem != null && cb.selectedItem != selectedItem) cb.selectedItem = selectedItem;
    if(cb.selectedIndex < 0) cb.selectedIndex = 0;
    dataProvider = cb.dataProvider;
   }
  }

  private function extendDP():void {
   dp.addItem("Item " + (dp.length +1));
   var ac:ArrayCollection = new ArrayCollection(dp.source);
   dp = ac;
  }

  private function reduceDP():void {
   dp.removeItemAt(dp.length -1);
   var ac:ArrayCollection = new ArrayCollection(dp.source);
   dp = ac;
  }
 ]]>
</mx:Script>

<mx:VBox>
 <mx:ComboBox dataProvider="{dp}" change="onChange(event)" updateComplete="onUpdateComplete(event)" />
 <mx:Button label="Extend dp" click="extendDP()" />
 <mx:Button label="Reduce dp" click="reduceDP()" />
</mx:VBox>

It creates a ComboBox and binds it to an ArrayCollection. The two buttons adds and removes items from the collection.

Johan Öbrink