Saturday, May 17, 2008    
Home My Books Blog ColdFusion About Me Back    

Calendar
<< Nov 2006 >>
S M T W T F S
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

Search

Categories
 • Adobe (61) [RSS]
 • AdobeMAX06 (45) [RSS]
 • AdobeMAX07 (59) [RSS]
 • AdobeMAX08 (6) [RSS]
 • AIR (96) [RSS]
 • Appearances (105) [RSS]
 • Books (66) [RSS]
 • CFEclipse (14) [RSS]
 • ColdFusion (1081) [RSS]
 • Flash (91) [RSS]
 • Flex (319) [RSS]
 • Jobs (81) [RSS]
 • JRun (12) [RSS]
 • Labs (27) [RSS]
 • LiveCycle (12) [RSS]
 • MAX (141) [RSS]
 • Regular Expressions (12) [RSS]
 • SQL (36) [RSS]
 • Stuff (492) [RSS]
 • Tips (CF Studio) (80) [RSS]
 • Tips (CF) (795) [RSS]
 • Tips (Dreamweaver) (91) [RSS]
 • Tips (Flex Builder) (2) [RSS]
 • Using CF (131) [RSS]
 • Wireless (96) [RSS]

Other BLOGs
 • Ray Camden
 • Tim Buntel
 • Sean Corfield
 • John Dowdell
 • Steven Erat
 • Brandon Purcell
 • Charlie Arehart
 • Full As A Goog

RSS Feeds
 • Feed
 • Subscribe

Join my mailing list and find out about new books and other topics of interest.

Thoughts, ideas, tips, musings, and pontifications (not necessarily in that order) by Ben Forta ...
NOTE: This is my personal blog, and the opinions and statements voiced here are my own.

Viewing By Entry / Main
November 22, 2006

Flex ComboBox With selectedValue Support

One of the things I like most about ColdFusion's <CFSELECT> tag is the SELECTED attribute, give it a value and it figures out which one to pre-select. The Flex ComboBox allows you to set selectedIndex (the relative element position) but not selectedValue. Actually, ComboBox does have a selectedValue property, but that is used to read the value of the selected item, and can't be used to set the value of the item to be selected.

Coincidentally, while I was working on this, both Scott Stroz and Ray Camden posted solutions to the exact same problem. Scott's solution involved calling a method to set the value, and I really think that the selectedValue property should be used to be consistent with how ComboBox itself works. Ray's solution allows for a property to be set (he defined a new property for this), but his solution would not work for me as my dataProvider was being populated after the control had been created (it is being populated by a call to a CFC).

So, here is my solution. It's bit more complex than what Scott and Ray suggested, but it does support selectedValue, it'll also allow that property to be changed as needed (even after control creation), and it also properly handles delayed dataProvider population.

Here is the code:

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">

   <mx:Script>
      <![CDATA[
         private var _selectedValue:String;
         private var bSelectedValueSet:Boolean = false;
         private var bDataProviderSet:Boolean = false;

         // Override committ, this may be called repeatedly
         override protected function commitProperties():void
         {
            // invoke ComboBox version
            super.commitProperties();

            // If value set and have dataProvider
            if (bSelectedValueSet && bDataProviderSet)
            {
               // Set flag to false so code won't be called until selectedValue is set again
               bSelectedValueSet=false;
               // Loop through dataProvider
               for (var i:int=0;i<this.dataProvider.length;i++)
               {
                  // Get this item's data
                  var item:String = this.dataProvider[i].data;
   
                  // Check if is selectedValue
                  if(item == _selectedValue)
                  {
                     // Yes, set selectedIndex
                     this.selectedIndex = i;
                     break;
                  }
               }
            }
         }

         // Trap dataProvider being set
         override public function set dataProvider(o:Object):void
         {
            // invoke ComboBox version
            super.dataProvider = o;

            // This may get called before dataProvider is set, so make sure not null and has entries
            if (o!=null && o.length)
            {
               // Got it, set flag
               bDataProviderSet = true;
            }
         }

         // set for selectedValue
         public function set selectedValue(s:String):void
         {
            // Set flag
            bSelectedValueSet = true;
            // Save value
            _selectedValue = s;
            // Invalidate to force commit
            invalidateProperties();
         }
      ]]>

   </mx:Script>

</mx:ComboBox>

And here is a simple test case:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:ns1="*">
<mx:Script>
   <![CDATA[
      [Bindable]
      private var comboData:Array=
      [{label:"Item1", data:"1"},
      {label:"Item2", data:"2"},
      {label:"Item3", data:"3"}];
   ]]>
</mx:Script>
<ns1:ComboBox2 dataProvider="{comboData}" selectedValue="3" />
</mx:Application>

Related Blog Entries

TrackBacks
There are no trackbacks for this entry.

No trackback URL. Trackbacks are only allowed via interactive form.

Comments
Ben - I like this way much better as it does feel more like native properties in Flex.
# Posted By Scott Stroz | 11/22/06 11:29 PM
Ben - quick question. You mentioned that the dataProvider was being populated by a call to a CFC. If you set selectedValue before the dataprovider is populated with data from the CFC, I assume the correct value will still be selected. How is this happening? Is commitProperties called when the dataProvider is populated with data?
# Posted By Scott Stroz | 11/22/06 11:35 PM
Scott, yes, I believe that that is the case.

--- Ben
# Posted By Ben Forta | 11/23/06 1:11 PM
Ben - Thanx! This opens up a lot of possibilities for other custom components.
# Posted By Scott Stroz | 11/24/06 9:24 AM
Ben, maybe I'm missing the point here, but ComboBox (and a few others like List and DataGrid ) not only offers the selectedIndex property to select an item by using a numeric index but also a selectedItem property which selects an item from the dataProvider by passing in a reference.
# Posted By Dirk Eismann | 11/28/06 2:25 AM
Lifesaver! I had written some really convoluted, long-winded function to set my selectedIndex property. This is great. Thanks again..
# Posted By Pete Capra | 11/29/06 7:32 PM
Works only if your OBJECT has the property "value" ... I think. It would be great if the Combobox has a property, where you can select the valueField (like labelField)
# Posted By Tristan Hauser | 11/30/06 6:42 AM
I extended the ComboBox a little bit. You can now define the dataField (Default: data), so you can easily point to the right field.

Here's the code:
http://www.tristanhauser.com/flex/ExtendedComboBox...
# Posted By Tristan Hauser | 11/30/06 7:58 AM
Thanks Ben! I'm new to flex, with a background in vb/access then java/swing then c#, and I expected combobox to do this out of the box, but your code works beautifully and gives me a look into how to extend components as well!
# Posted By Jack Freudenheim | 12/5/06 10:14 AM
Ben,

I noticed in your example you used an Array with static data to set the combo box values. Would it be possible to show an example using mx:WebService?
# Posted By Andrew | 12/10/06 7:46 AM
Ben - thank you so much for this - i just saved a bunch of time trying to figure out how to set that selectedIndex. Just wanted you to know that this is working and we thank you!
# Posted By Mitch Aunger | 1/5/07 12:11 PM
this is my solution:
public function initCombobox(obj:Object):void{
            for(var i:int=0;i<obj.dataProvider.length;i++){
               var selected:String = obj.dataProvider[i].selected;
               
               if(selected != null){
                  if(selected == "true"){
                     obj.selectedIndex = i;
                     break;
                  }
               }
            }
         }

<area>
<item label="??" data="-1" />
<item label="??" data="0570" />
<item selected="true" label="??" data="0571" />
<item label="??" data="0572" />
<item label="??" data="0573" />
<item label="??" data="0574" />
<item label="??" data="0575" />
<item label="??" data="0576" />
<item label="??" data="0577" />
<item label="??" data="0578" />
<item label="??" data="0579" />
<item label="??" data="0580" />
</area>
# Posted By wujian | 1/17/07 1:33 AM
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   <mx:Script>
      <![CDATA[
         public function initCombobox(obj:Object):void{
            for(var i:int=0;i<obj.dataProvider.length;i++){
               var selected:String = obj.dataProvider[i].selected;
               
               if(selected != null){
                  if(selected == "true"){
                     obj.selectedIndex = i;
                     break;
                  }
               }
            }
         }
      ]]>
   </mx:Script>
   <mx:ArrayCollection id="ac">
      <mx:Array>
         <mx:Object label="A" data="1"/>      
         <mx:Object label="B" data="2"/>      
         <mx:Object label="C" data="3"/>      
         <mx:Object label="D" data="4"/>      
         <mx:Object label="E" data="5" selected="true"/>      
         <mx:Object label="F" data="1"/>      
         <mx:Object label="G" data="1"/>      
      </mx:Array>
   </mx:ArrayCollection>
   <mx:ComboBox id="testComb" dataProvider="{ac}" x="37" y="64"></mx:ComboBox>
   <mx:ComboBox id="testComb2" dataProvider="{ac}" creationComplete="initCombobox(testComb2)" x="37" y="94"></mx:ComboBox>
</mx:Application>
# Posted By wujian | 1/17/07 1:51 AM
Ben Forta you rock! I'm new to Flex and been having some adjustments coming from a pure Cold Fusion background. I was surprised to find the orginal Flex Combobox without a direct selectvalue property. I spent too much time trying to figure this out. I'm so glad you write this custom component....life saver.
# Posted By Tommy 10 Fingers | 2/12/07 8:20 PM
A great help - the only thing I added was setting selectedIndex=-1 before the search - otherwise, if the data is not found it will show whatever the previously selected value was. This can happen when used with a database which has some incorrect or empty values, and if it shows the previous value it is not obvious there is a problem. With -1, the CB is blank, making it clear.
# Posted By Neil | 3/19/07 12:26 PM
Thanks to wujian's post I was finally able to overcome this frustrating obstacle. However being a coldfusion /.net developer, it seems to me that this is something that should be built into the component. I'm just learning flex/as3 and finding I'm writing volumes of code to do the simplest mundane things. This is what makes ASP.NET so popular, the controls do all the heavy lifting and much of this grunt coding is built into the controls themselves. Flex is supposed to be an RIA langueage remember. Ben please pass my frustions and opinions on to the flex team. I DONT WANT TO WRITE CODE THAT SHOULD BE BUILT INTO A COMPONENT!
Just my 2 cents. I feel better now. :-)
# Posted By GSuhr | 4/27/07 11:47 AM
Ben (or anyone, for that matter!), not sure if this thread is still monitored or not but I have a question:

I have duplicated this control - THANKS - by extending mx:List. Because this list is necessarily several thousand items long (everyone in our firm), I have added the following to the logic in order to show the highlighted dp item:

...
this.selectedIndex = i;
//added:
this.verticalScrollPosition = i;
...

It works great, except for the first time that it's called - the correct item is selected, but the verticalScrollPosition doesn't take effect. If you scroll down the list you can see that the correct item is selected - it just doesn't scroll down to that position. I'm assuming this is because the parent component hasn't been completely rendered yet (this is a Cairngorm app where selectedValue property is bound to a property of a value object in the modelLocator), but the creationComplete event is dispatched before the selectedValue setter is called so I'm at a loss. Each subsequent view of that screen correctly scrolls to the item in the list.

Any advice on how to force this to scroll on the first call?

Thanks in advance,
Joe
# Posted By Joe | 5/10/07 1:03 PM
(flex newbie here)

thanks for this... but how do i 'bind' the selected index to a datagrid selection?
ie, something like, ideally:
<comp:ComboBox2 x="112" y="39" dataProvider="{rstClients}" selectedValue="<b>{surveyGrid.selectedItem.SCLIENTNAME}</b>" labelField="SCLIENTNAME" width="205" />

compared to textinput controls' bindings, triggering combobox updates through datagrid's itemfocusin seems 'dirty'.
# Posted By Leif | 6/2/07 7:49 PM
I have slight twist on this, I have cfselect that gets its data from a cfdirectory tag. The cfselect provides the user with a list of xml file in a directory. After the user selects an xml file I need to read the values in the xml file and put them into text boxes on the flash form.

I can get everything but cannot get the value of the selectedItem from the cfselect combo box.

Any suggestions here as I know nothign about flex

Thanks

Jim
# Posted By James Schell | 6/12/07 10:05 PM
This is a very delayed reply to Joe's query above.
You could try this.scrollToIndex(i);
# Posted By Elton | 7/6/07 12:08 PM
thanks Elton - Because of real estate limitations, I ended up switching back to the data aware combo box class.

In theory these should be pretty darned identical in behavior, but I think what might have gotten it to work was setting the creationPolicy="all" attribute on the application.

Not sure whether this was definitely the fix, but it sure did seem to help with a lot of other little gotcha's throughout the application and eliminated a bunch of null checking, etc.

Just thought I would add this note to the thread incase it helps someone else.
# Posted By Joe | 7/9/07 4:38 PM
I tried the this.scrollToIndex(i); It doesn't scroll to the right position and my datagrid shows empty rows when I scroll up and down with the mouse. And then they will appear after a while. Any suggestions?

Jaqueline
# Posted By jaq | 7/21/07 1:26 AM
Hi,

Another newbie to Flex here..

I'm trying to Bind this to a selectedItem from a DataGrid to a Combo box please can someone tell me if this is possible with this Combobox as Flex does no support SelectedItem..

I see you can use a static value in the SelectedValue and it works fine, but if you put a Dynamic Value in ie. selectedValue="{datagrid.selectedItem.column}" it doesn't seem to work..

Any adive would be great..

Matt
# Posted By Matt Hart | 7/22/07 6:11 PM
Thank you. I had the same problem of the dataprovider not being populated at the time of the control creation. This is a very clean implementation.
# Posted By Liz | 9/19/07 12:28 PM
I too am grateful to you Ben for posting this solution. I spent no less than 10 hours f'ing with a stupid ComboBox trying to get it to do something I could EASILY do in HTML, JSP, or JSF years ago! It's utterly amazing that Adobe has not provided an OOB solution for this common scenario.

I'm new to Flex and recently committed to using it to develop a large portion of my small startup company's product, but this ComboBox nonsense is making me wonder if I made the right choice. How many more wasted days will I experience chasing solutions to problems that should be part of the OOB product.

Thanks again Ben!

Tom
# Posted By Tom | 9/24/07 7:31 PM
Hi Ben,

Thanks for this great extension to the ComboBox! Thanks mostly for commenting the code because I was having so much trouble getting this thing to work. It turned out I was setting the dataProvider with databinding, BEFORE I populated the dataProvider.

Making the call to set dataProvider right after populating my label data object did the trick. I'm planning on always using this ComboBox.

Question, why doesn't the Flex framework already define a selectedValue method for mx:ComboBox in the first place, does it have anything to do with data binding?

thanks,

Derek
# Posted By Derek | 9/25/07 12:48 AM
Thanks so much. I was fortunate enough to do a quick search before I wasted too much time trying to find the "selectedValue" property. This has been a great help, and it is very much appreciated!
# Posted By David | 10/16/07 12:51 PM
Tristan, great work! :-) This is what I really wanted!

Let's hope that Adobe will add this into Flex 3 .... it's really not to have this very basic functionality in a combobox!

thnx
# Posted By George | 10/21/07 5:37 PM
I like this way much better as it does feel more like native properties in Flex.
# Posted By seo services | 3/20/08 4:19 AM
Great post! My previous - less elegant solution was to use a helper function to convert the item to an index...

public function findItemIndex( dp:IList, data:String ):int
{
for( var i:int = 0; i < dp.length; ++i )
{
if( dp.getItemAt(i).data == data )
return i;
}
return -1;
}

&lt;mx:ComboBox dataProvider="{myDP}" selectedIndex="{findItemIndex(myDP, selectedItem) }" /&gt;
# Posted By Ryan Phelan | 4/21/08 7:45 PM
This opens up a lot of possibilities for other custom components.
# Posted By rimona | 4/26/08 12:17 AM

  © Copyright 1997-2008 Ben Forta, All Rights Reserved