Flex ComboBox Fix

Ok, this one's been driving me nuts, so I finally fixed it myself.

The problem is with the infamous Flex ComboBox control. When you change data providers for the control at runtime, you lose the previously selected index.

Really.

Finding no joy for a solution online, I started tinkering with the SDK source code to see what was up:

http://tools.assembla.com/flexsdk/browser/mx/controls/ComboBox.as

I noticed a "set dataProvider" function on line 669 which was the culprit. It destroys the dropdown and invalidates any of the previous properties of the control. I'm guessing this is what's wiping out the selected index!

So I extended the ComboBox and added a property which stores the selected index in a separate variable. After calling:

// This setter destroys the selectedIndex property. Nice job...
super.dataProvider = dp;

...I restore the selected index to its saved value.

I set the value when the object is first rendered and whenever there's a change event on the ComboBox.

See the attached code ('download' link below) for a sample and the shiny new ComboBox2.

package components {

   import mx.controls.ComboBox;
   import mx.events.ListEvent;
   import flash.events.Event;

   public class ComboBox2 extends ComboBox {

      private var savedSelectedIndex:int;
      public var selectionChanged:Boolean = false;

      public function ComboBox2( ) {
         super();
         this.savedSelectedIndex = this.selectedIndex;
         this.addEventListener( ListEvent.CHANGE, onChange );
         this.addEventListener( Event.RENDER, onRender );
      }

      // On first render of the ComboBox, capture the selected index
      private function onRender( event:Event ):void {
         savedSelectedIndex = this.selectedIndex;
         this.removeEventListener( Event.RENDER, onRender );
      }

      // On change of selection on the ComboBox, capture the selected index
      private function onChange( event:ListEvent ):void {
         savedSelectedIndex = this.selectedIndex;
      }

      override public function set dataProvider( dp:Object ):void {

         super.dataProvider = dp;

         // Yipee! Restore the selectedIndex:
         this.selectedIndex = savedSelectedIndex;
    }
   }
}

I could not have done this before the open source release of the Flex SDK to the world. Thanks Adobe! (But opinion withheld on the ComboBox;)

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Tony Fendall's Gravatar This sounds like the expected behaviour of a ComboBox to me. In most cases there would be no relation between two different data providers supplied to the control, so the fact that the third item happened to be selected before the change wouldn't be rellevant.

Nice work around though. For potential reuse, you could add a rememberSelectedIndex:Boolean property to the control to handle this.
# Posted By Tony Fendall | 7/24/07 10:22 PM
Chad Upton's Gravatar I like this! But, I can't think of a scenario when I might use it. Usually, if I'm changing the dataprovider it is a matter of adding or removing data to/from that dataprovider. I'm pretty sure the selectedIndex sticks for that. Maybe I'm missing something obvious; could provide an example of when this is handy?
# Posted By Chad Upton | 7/25/07 9:12 AM
Oliver Merk's Gravatar @Tony: I thought about that boolean as well;) I guess I could argue that if the control and data are truly separate, why does changing the data change the selected index back to 0? I think the control's selectedIndex should not be affected by the data changing.

@Chad: I ran into it on a project where we had to switch languages at runtime, and the previous selection would be lost. In the download zip there is an example of the selectedIndex being re-set to 0 after the dataProvider changes.
# Posted By Oliver Merk | 7/25/07 10:21 AM
Tim Hayes's Gravatar Oliver, this is exactly what I needed. I was having trouble with the ComboBox losing its index after the RENDER event. I mixed both my extended ComboBox with some of your code to make an advanced ComboBox and it works well. The one thing I changed was the removeEventListener from onRender, as I'm using it with a system of States so it gets back in again and again :)
# Posted By Tim Hayes | 8/2/07 3:25 PM
Shaggy's Gravatar Hi guys, how are ya?
Listen, i´m extending ComboBox too. Whatever i do i don´t preserve the IFactory interface that it implements originally. That means i can´t do something like:

<components:Combo2>
<mx:itemRenderer>
<mx:Component>
<mx:Image......./>
</mx:Component>
</mx:itemRenderer>
</components:Combo2>

Does anybody have a clue?
# Posted By Shaggy | 8/28/07 10:10 AM
Shawn's Gravatar Thanks for this. I was running into a problem in which a data provider bound to a combobox was based on a form the user could update. When the data in the data provider changed, the listed items in the combobox would update, except the selected item would still show the data from the previous instance of the data provider -- in other words, the item listed at the top of the combo box would be a value that didn't exist in the list of choices. Resetting the data provider fixed this, but I would then lose the selected index. Your fix is now making this work.
# Posted By Shawn | 1/4/09 5:39 PM
Fahad's Gravatar Great fix, the issue was driving me nuts.

Thanks
# Posted By Fahad | 3/9/09 3:47 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.