I have been following Ray Camden's series of posts on a Flex project he is working on. During this project, he discovered that sometimes functionality you might expect does not exist (Though, in his example, the functionality he was looking for does exist). I ran into a issue like this with <mx:ComboBox> on a recent project.
Let's say you have a form that allows you to update information about widgets, and one piece of information is the type of widget. The type of widget is chosen from a comboBox, however, the value stored in the database is different than what you see in the combo box (think of an HTML select box - often we display a nice user friendly label, but store the 'value' which is some kind of an ID). There is no native method (at least not that I could find), that allows you to set the selected item based on the value of that item. I could, however, loop over the data or dataprovider for the combo box and compare the value to that data and set the selectedIndex accordingly, however, this seemed...ugly, and could cause issues should I need to use this over and over. The solution was actually quite simple, custom components.
Flex allows you to build custom components, based on native Flex containers or controls, that can each contain their methods, or even overwrite native methods. I decided to build a custom component with the logic necessary to select an item based on the value.
Before we begin, create a new Flex project. For this demo, you can just leave all the default values.
One of the first things I do when starting a Flex project is to add a 'components' directory to my Flex project. You can name this anything you want, I prefer 'components'.
To create a new component, right click on the 'components' folder and choose 'New --> MXML Component'. Give the component a name with a .mxml file extension. In this demo, we will name it 'customComboBox.mxml'. In the 'Based On:' form field, select 'ComboBox', and then click 'Finish'.
Congratulations, you just created a custom Flex component!
In order to use you component, you first need to add a namespace the <mx:Application> tag. You need to add xmlns:comp="components.*". Assuming you did n ot make any changes acfter creating the Flex project, your main application page should look like this:
2</mx:Application>
To use our custom component, simply add the following between the opening and closing <mx:application> tags:
2 <comp:customComboBox id="myCombo"/></mx:Application>
Now if you run the application, you will see an empty combo box on the page. Before we get into modifying the component, let's add some data that can be used to populate the combo box.
Here we created an variable as an Array with an item that have a label and data (Think of labels as what is in between <option></option> tags, and think of data as the value attribute of the <option> tag. We then set the dataProvider for our custom combo box to this variable. If you view the application now, you will see that our combo box now has data associated with it.
We can now modify our custom component to give us the custom functionality we desire. Open up '/components/customComboBox.mxml' if it is not already open and add the following code between the opening and closing <mx:ComboBox> tags.
Let's break down this code. First, we are creating a public function named selectedItemByValue. it needs to be public so that you can call this method from outside of the component. This method takes one argument, which in this case must be an integer. Nothing is returned from the method.
Next, we loop over the dataprovider and check to see if the value passed in equals the 'data' property of our dataprovider, if it does, we set the selectedcIndex of the comboBox to the current iteration of our loop. If it doesn't match, we set the selectedindex to 0. Id the value passed in does not match any items in the dataprovider, the forst item in the dataprovider will be shown.
If you compile and view the application, you will see nothing changes in what we can see. Now we need to trigger the new method we just created. For this demo, we will create 3 buttons and each button, when clicked, will change the comboBox to show the item with the matching 'data' property.
Add this code to your main application file after our custom comboBox.
You can see here that all we are doing is calling the selectedItemByValue() method of our custom combo box and passing in different values depending on which button is clicked.
Save and compile your application and then view it. You will see that as you click each button, the appropriate item displays in the combo box.
You may want to keep this custom component in a place where you can easily copy it into other applciations. I find that I use it frequently.




14 comments
ML.
Given the following snippet:
var myData:Array = [{label:'data1',data:1},{label:'data2',data:2},{label:'data3',data:3}]
Doing something like this works fine:
this.dataProvider.selectedItem = myData[2];
So you don't actually need to compare an invidual VALUE and set the selectedItem, all you have to do is pass in the object itself. That means that you can, in combination with the filterFunction of an ArrayCollection (which is what queries and structs are when passed from CF to Flex) to find the item you want and set the selectedItem to that instance. That is:
private function getMyRecord(obj:Object):boolean { obj.ColName == this.myId; }
In your remoting result handler, set the filterFunction on the result, call reset and get a handle on the correct element in the collection (which should be the only one available). Then reset the result, set it to the dataprovider and set the selectedItem to the handle you got from the filterFunction.
Be it known that there are probably gotchas here because I haven't actually TESTED this, just looked over the docs on the subject... but using the filterFunction property will get you the one item that matches your value, and setting the object to the selectedItem from the get-go is a bit more "elegant". Play with it... blog what you find out. :)
J
Just wanted to say thanks for this post! I've been trying to figure out a reliable and good way to do this and your post really helped me on a project I'm wrapping up!!
Also, I'm a big golfer and if you ever get a chance, come play Fairway Pines outside Ridgway, Colorado (we're in the Southwest Corner of the state not too far from Telluride). It's a great mountain course (elevation ~8000 feet) with views of the San Juan mountains (several 14,000+ peaks to see from each hole).
Thanks, again!
Craig
Thanks
George
private function sendFormdata4():void {
var myobj:Object = new Object();
myobj.AccNum = AccNumLabel.text;
myobj.DBA = DBALabel.selectedLabel;
The DBALabel is the id of the combobox.
I have a handle function for the combo data.
public function handleAccountsResult(event:ResultEvent):void{
myAccounts = Accounts.Accounts.lastResult;
var prompt:Object = new Object();
prompt.data = null;
prompt.label = "Select Account";
myAccounts.addItemAt( prompt, 0 );
DBALabel.selectedIndex = 0;
}
All that happens when I send a new record is that the label "Selected Account" goes into the DBA column.
Any thoughts?
Thanks
Thanks a lot for your post. I was facing the same problem and your post helped me a lot.
Thank you very much.