Flex: Country Aware States ComboBox

Alex had created some extensions to ComboBox that handled pre-population of Country and State information. They solved his problem and hopefully worked for others as well, but i just had the occasion to start using them and ran into some issues.

The first issue is that they extend ComboBox. When you need to set the value of a ComobBox you have to go through the grief of iterating over a loop. Luckily, I've already addressed the needed additions to support a ComboBox selectedValue property. So getting this up and running, at least initially, was as easy as changing ComboBox to eComboBox (you don't have to explicitely import the class if you put the definition in the same package).

The second issue is that needed states entry varies with the country. The US has its states and territories, as does Canada and probably some other countries too (If you aren't a mostly English speaking country on North America do you even exist? - just joking) so if the country input is open ended you might find yourself wanting comboboxes as well as textinputs. I originally had gone through the annoying process of maintaining two discrete comboboxes and a textinput and logic to control the visible and includeInLayout properties; that gets old quickly. Instead, I just wanted a single entry for the State information with a common property for setting and getting the selected value.

To make my life easier, I decided to just extend what Alex had created by just consolidating the XML dataProviders. For some reason, he had already included a country property so it was easy enough to group them together so as to be able to filter them later:

<states>
<state label="Alabama" value="AL" country="US" />
<state label="Alaska" value="AK" country="US" />
<state label="Arkansas" value="AR" country="US" />
<state label="Arizona" value="AZ" country="US" />
<state label="California" value="CA" country="US" />
<state label="Colorado" value="CO" country="US" />
<state label="Connecticut" value="CT" country="US" />
<state label="District of Columbia" value="DC" country="US" />
<state label="Delaware" value="DE" country="US" />
<state label="Florida" value="FL" country="US" />
<state label="Georgia" value="GA" country="US" />
<state label="Hawaii" value="HI" country="US" />
<state label="Idaho" value="ID" country="US" />
<state label="Illinois" value="IL" country="US" />
<state label="Indiana" value="IN" country="US" />
<state label="Iowa" value="IA" country="US" />
<state label="Kansas" value="KS" country="US" />
<state label="Kentucky" value="KY" country="US" />
<state label="Louisiana" value="LA" country="US" />
<state label="Maine" value="ME" country="US" />
<state label="Maryland" value="MD" country="US" />
<state label="Massachusetts" value="MA" country="US" />
<state label="Michigan" value="MI" country="US" />
<state label="Minnesota" value="MN" country="US" />
<state label="Mississippi" value="MS" country="US" />
<state label="Missouri" value="MO" country="US" />
<state label="Montana" value="MT" country="US" />
<state label="Nebraska" value="NE" country="US" />
<state label="Nevada" value="NV" country="US" />
<state label="New Hampshire" value="NH" country="US" />
<state label="New Jersey" value="NJ" country="US" />
<state label="New Mexico" value="NM" country="US" />
<state label="New York" value="NY" country="US" />
<state label="North Carolina" value="NC" country="US" />
<state label="North Dakota" value="ND" country="US" />
<state label="Ohio" value="OH" country="US" />
<state label="Oklahoma" value="OK" country="US" />
<state label="Oregon" value="OR" country="US" />
<state label="Pennsylvania" value="PA" country="US" />
<state label="Rhode Island" value="RI" country="US" />
<state label="South Carolina" value="SC" country="US" />
<state label="South Dakota" value="SD" country="US" />
<state label="Tennessee" value="TN" country="US" />
<state label="Texas" value="TX" country="US" />
<state label="Utah" value="UT" country="US" />
<state label="Vermont" value="VT" country="US" />
<state label="Virginia" value="VA" country="US" />
<state label="Washington" value="WA" country="US" />
<state label="West Virginia" value="WV" country="US" />
<state label="Wisconsin" value="WI" country="US" />
<state label="Wyoming" value="WY" country="US" />

<state value="AB" label="Alberta" country="CA" />
<state value="BC" label="British Columbia" country="CA" />
<state value="MB" label="Manitoba" country="CA" />
<state value="NB" label="New Brunswick" country="CA" />
<state value="NL" label="Newfoundland and Labrador" country="CA" />
<state value="NT" label="Northwest Territories" country="CA" />
<state value="NS" label="Nova Scotia" country="CA" />
<state value="NU" label="Nunavut" country="CA" />
<state value="ON" label="Ontario" country="CA" />
<state value="PE" label="Prince Edward Island" country="CA" />
<state value="QC" label="Quebec" country="CA" />
<state value="SK" label="Saskatchewan" country="CA" />
<state value="YT" label="Yukon" country="CA" />

<states><state value="" label="None" country="OT" /></states>
</states>
[Notice that there is a place holder for other countries.]

So the gist is that when the country property is set, we will filter the XML based on the @country attribute. This might look like:

public function set country(value:String):void {

editable = false;
_country = value;
switch (_country) {
case "US":
dataProvider = statesAll..state.(@country=="US");
break;
case "CA":
dataProvider = statesAll..state.(@country=="CA");
break;                
default:                                        
dataProvider = statesAll..state.(@country=="OT");
editable = true;
selectedValue = "";
text = "";                    
break;
}            
}

So when the country is set we update the dataProvider to reflect the properly filtered States in the XML. We also adjust the editable property so that countries with unknown states, or optional ones, can type in whatever they want. The only problem is that the above code will drive you nuts with Flex 3.5 (haven't tested this with other Flex versions). What will happen is that even though the country will be properly updated and the dataprovider will be correctly changed, the dropdown menu will not be updated correctly. This little bug is wonderfully maddening. Happily, however, I found the resolution to the problem at "Flex 3.5.0; Update ComboBox display list upon dataprovider change" at stackoverflow. Anyway, the function, if you want it to behave predictably, ought to look like:

public function set country(value:String):void {

editable = false;
_country = value;
switch (_country) {
case "US":
dataProvider = statesAll..state.(@country=="US");
dropdown.dataProvider = statesAll..state.(@country=="US");
break;
case "CA":
dataProvider = statesAll..state.(@country=="CA");
dropdown.dataProvider = statesAll..state.(@country=="CA");
break;                
default:                                        
dataProvider = statesAll..state.(@country=="OT");
dropdown.dataProvider = statesAll..state.(@country=="OT");
editable = true;
selectedValue = "";
text = "";                    
break;
}            
}

The last little bit to accomplish is that the eComoboBox doesn't expose the selectedValue as a getter. Since we want to grab the @value of the selectedItem when the state is selected through the dropdown and the text of the field when it is entered manually, the getter has to also be country aware. Also, the setter is bit more complicated for the same reason:


override public function set selectedValue(s:String):void {
switch (_country) {
case "US":
case "CA":
// Set flag
bSelectedValueSet = true;
// Save value
_selectedValue = s;
break;
default:
_selectedValue = s;
this.text = s;
break;
}
// Invalidate to force commit
invalidateProperties();
}
        
public function get selectedValue():String {
var _value:String = "";
switch (_country) {
case "US":
case "CA":
_value = this.selectedItem.@value;
break;
default:
_value = this.text;
break;
}
return _value;
}

So, putting everything together, here is an example of a flex country aware state combobox with source.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.001. Contact Blog Owner