Menu

Spark ComboBox

SourceForge Editorial Staff
There is a newer version of this page. You can find it here.
Jason Szeto (Dev) Jacob Goldstein (QA) # Functional and Design Specification ---- ## Glossary ---- * _ComboBox_ - a component that consists of a TextInput, a button and a List popup * _DropDownList_ a non-editable ComboBox that does not contain a TextInput * _filtering_ the behavior of narrowing down the set of items based on what the user has typed * _input string_ - the string typed into the TextInput * _matching item_ - the item in the dataProvider that is a string match to the input string ## Summary and Background ---- The ComboBox component is similar to a DropDownList but has a TextInput instead of a Label. A user can type into the TextInput and the dropDown will scroll to and highlight the closest match. Users are allowed to type in an item not found in the dataProvider. With this behavior, a ComboBox acts as a list of suggested values, while a DropDownList acts as a list of possible values. Much of the functionality and API of ComboBox is inherited from DropDownList. [DropDownList Spec](http://opensource.adobe.com/wiki/display/flexsdk/Spark%2BDropDownList) ## Usage Scenarios ---- Mick is creating an online survey for the PitchSpoon music site. One of the questions is to select the "Best Rock Band of All Time." Since the list of choices is long and he doesn't want to take too much screen real estate, he uses a ComboBox to capture the answer. He also wants to allow write-in answers which is why he uses a ComboBox instead of a DropDownList. He adds the ComboBox in his application, hooks up the dataProvider to his back end data. Jonathan is creating a drawing application. He needs a way for the user to choose a stroke weight. The stroke weight can range in size from 0 to 100. He decides to use a ComboBox to provide ten commonly used weights but still allow the user to type in a weight. Each stroke weight shown in the dropDown is accompanied by a black line that shows a visual representation of the stroke weight. Margo is creating a web browser application. She uses a ComboBox for the URL location bar. She uses the client's SharedObject to retrieve recently typed URLs and passes that into the ComboBox's dataProvider. Each dropDown item shows the fully qualified URL and a page icon (if one exists). When the user types in a URL and commits it (closes the ComboBox), then that URL is written out to the SharedObject. ## Detailed Description ---- The ComboBox component is a DropDownListBase with a _textInput_ skin part of type TextInput. DropDownList will be refactored into DropDownList and DropDownListBase. DropDownList will add support for a label skin part. For ComboBox, the user can type into the TextInput control. The property _openOnInput_ controls whether the dropDown will open upon typing. If true, the dropDown will open and scroll to and highlight the closest matching item in the dataProvider. By default, it is true. The user is allowed to type in an item that isn't in the dataProvider. In this case, the selectedIndex will be _CUSTOM_SELECTED_ITEM_ and the selectedItem will be an object constructed from the input string. ComboBox will provide a property, _labelToItemFunction_, which is a Function that is called to convert the input string into an item. The default matching algorithm uses some basic string comparison. If an input string of length _n_ is equivalent to the first _n_ characters of an item (ignoring case), then it is a match to that item. For example, 'aRiz' is a match to "Arizona" while 'riz' is not. The property _itemMatchingFunction_ is called to return a set of indicies in the dataProvider that match the input string. Developers can pass in their own function to customize the matching algorithm. The ComboBox skin is very similar to DropDownListSkin except that it replaces the Label skin part with a TextInput skin part. ### TextInput Proxy The ComboBox will proxy some events and properties from TextInput. Properties: * maxChars * restrict Styles: * paddingLeft * paddingRight * paddingBottom * paddingTop Some properties don't make sense to expose since their value should never change (ex. displayAsPassword, editable, selectable). The properties that are not exposed are provide advanced functionality and can be accessed through the textInput skin part. Inheriting styles are not directly exposed because they get passed down to the textInput. Non-inheriting styles are not directly exposed because you can use Advanced CSS to specify the styles. The exception are the padding styles which are defined on ComboBox as a convenience for developers. None of the events are exposed since they would only be used by advanced developers. These events can be accessed by listening to the events on the textInput skin part. ### Mouse and Keyboard interactions Keyboard interactions while closed: * Editing the textInput (ie. typing a letter or deleting characters) will open the dropDown. The dropDown will scroll to and highlight the closest match. If there is no match, then no item will be highlighted. If there is a match, the textInput will contain the match, with the non-typed characters selected. * Pressing LEFT/RIGHT/SHIFT-LEFT/SHIFT-RIGHT/SHIFT-UP/SHIFT-DOWN in the textInput behaves the same as in TextInput * Pressing UP/DOWN/HOME/END/PGUP/PGDN behaves the same way as in DropDownList. The selectedItem will change depending on upon which navigation key was pressed. * Pressing CTRL-DOWN will open the dropDown Keyboard interactions while open: * Editing the textInput will scroll to and highlight the closest match. If there is no match, then no item will be highlighted. * Pressing LEFT/RIGHT/SHIFT-LEFT/SHIFT-RIGHT/SHIFT-UP/SHIFT-DOWN in the textInput behaves the same as in TextInput * Pressing UP/DOWN/HOME/END/PGUP/PGDN will change the selectedItem and update the textInput to that item. The selectedItem will change depending on upon which navigation key was pressed. The textInput text will be selected. * Pressing ENTER will close the dropDown. It will commit the highlighted item if one exists. If no highlighted item exists, then it will commit the input string. * Pressing CTRL-UP will close the dropDown and commit the input string. * Pressing ESC will close the dropDown and cancel the commit. The selectedItem will not change, but the textInput text will remain the same. Mouse interactions while closed: * Clicking in the textInput will put focus in the textInput. If it was not previously in focus, then all of text in the textInput will be selected. Otherwise, it will behave the same as TextInput. * Clicking on the openButton will open the dropDown, highlight the closest match to the input string and select the non-typed characters. Mouse interactions while open: * Clicking in the textInput will put focus in the textInput. If it was not previously in focus, then all of text in the textInput will be selected. Otherwise, it will behave the same as TextInput. * Clicking on the openButton will close the dropDown and commit the input string. It will remove the focus ring from the ComboBox and remove focus from the textInput. ### B-Features **Filtering** When the user types into the TextInput, only items that match the input string will appear in the dropDown. The dropDown will still scroll to and highlight the closest matching item. The ComboBox will only support filtering if the dataProvider implements ICollectionView. ComboBox filtering uses the built-in filtering support in the implementors of ICollectionView, such as ArrayCollection. The default filtering algorithm uses the same algorithm as the matching algorithm described previously. The property _filterFunction_ points to a function that is passed to ICollectionView.filterFunction. This function returns true if the item matches the input string. **Allow user-defined selectedItem** By default, the ComboBox will allow the user to type in a value that is not in the dataProvider. The _allowCustomSelectedItem_ property controls whether or not the user can commit an item not found in the dataProvider. **Add State support** Add in support for putting the ComboBox into different states. Possible states include _itemSelected_, _noItemSelected_, and _itemMatched_. By having these states, the skin could change its appearance based on which state it is in. **Prompt Support** Support the prompt property. If prompt is set, then the prompt will be displayed in the TextInput if selectedIndex == NO_SELECTION. The prompt will never be committed as the selectedItem. The prompt will be displayed in another color/alpha text style. New style properties will need to be added for this support. ## API Description ---- _Additions to MXML Language and ActionScript Object Model_ _Include the relevant API for this feature using the following example as a guideline. Make sure you indicate whether APIs are public or protected. You do not need to present private or mx_internal APIs here._ package spark.components { import mx.controls.ComboBox; /** * Botttom inset in pixels for the textInput * * @default 3 */ Style(name="paddingBottom", type="Number", format="Length", inherit="no") /** * Left inset in pixels for the textInput * * @default 3 */ Style(name="paddingLeft", type="Number", format="Length", inherit="no") /** * Right inset in pixels for the textInput * * @default 3 */ Style(name="paddingRight", type="Number", format="Length", inherit="no") /** * Top inset in pixels for the textInput * * @default 5 */ Style(name="paddingTop", type="Number", format="Length", inherit="no") public class ComboBox extends DropDownListBase { /** * Optional skin part that holds the input text or the selectedItem text */ SkinPart(required="false") public var textInput:TextInput; /** * Static constant representing the value "custom selectedItem" */ public static const CUSTOM_SELECTED_ITEM:int = -3; public function ComboBox() { super(); } /** * The function referenced by this propery is called when textInput's text * is committed and is not found in the dataProvider. * * The function signature is this: * * function myLabelToItem(value:String):Object * * The function returns an Object that should be the same type as the items * in the dataProvider. * * If the value is null, then this function will not be called and the selectedItem * will be set to the input string. * * @default null */ public function set labelToItemFunction(value:Function):void; public function get labelToItemFunction():Function; /** * If true, the dropDown will open whenever the user edits the textInput. * * @default true */ public function set openOnInput(value:Boolean):void; public function get openOnInput():Boolean; /** * The function referenced by this property takes an input string and returns * the items in the dataProvider that match the input. * The items are returned as a Vector of indicies in the dataProvider. * * The function signature is this: * * function myMatchingFunction(comboBox:ComboBox, inputText:String):Vector.<int> * * If the value is null, the ComboBox will find matches using the following algorithm: * * If an input string of length n is equivalent to the first n characters * of an item (ignoring case), then it is a match to that item. For example, 'aRiz' * is a match to "Arizona" while 'riz' is not. * * @default null */ public function set itemMatchingFunction(value:Function):void; public function get itemMatchingFunction():Function; //////////////////////////////////////////////////////////////// // TextInput Proxy Properties and Methods //////////////////////////////////////////////////////////////// /** * The maximum number of characters that the textInput can contain, as entered by a user. * * @default 0 */ public function set maxChars(value:int):void; public function get maxChars():int; /** * Indicates the set of characters that a user can enter into the textInput. * * @default "" */ public function set restrict(value:String):void; public function get restrict():String; //////////////////////////////////////////////////////////////// // B-Features //////////////////////////////////////////////////////////////// /** * If true, then the user can commit the text in the textInput even if it is * not found in the dataProvider. * * @default true */ public function set allowCustomSelectedItem(value:Boolean):void; public function get allowCustomSelectedItem():Boolean; /** * The filtering function passed to ICollectionView.filterFunction. */ public function set filterFunction(value:Function):void; public function get filterFunction():Function; } } ## B Features ---- * Filtering * Allowing user-defined selectedItem * States * Prompt All are described in the Detailed Description section ## Examples and Usage ---- <combobox width="140"> <dataprovider> <arraycollection> <string>1. Alabama</string> <string>2. Alaska</string> <string>3. Arizona</string> <string>4. Arkansas</string> <string>5. California</string> </arraycollection> </dataprovider> </combobox> \\ <s:skin xmlns:local="*" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" alpha.disabled=".5"> <fx:metadata> HostComponent("ComboBox") ]]> </fx:metadata> <s:states> <s:state name="normal"> <s:state name="open"> <s:state name="disabled"> </s:state></s:state></s:state></s:states> <s:popupanchor id="popUp" displaypopup.normal="false" displaypopup.open="true" includein="open" left="0" right="0" top="0" bottom="0" itemdestructionpolicy="auto" popupposition="below" popupwidthmatchesanchorwidth="true"> <s:group id="dropDown" maxheight="134" minheight="22"> <s:rectangulardropshadow blurx="20" blury="20" alpha="1.0" distance="5" angle="90" color="#000000" left="0" top="0" right="0" bottom="0"> <s:rect left="0" right="0" top="0" bottom="0"> <s:stroke> <s:solidcolorstroke color="0x686868" weight="1"> </s:solidcolorstroke></s:stroke> </s:rect> <s:rect id="background" left="1" right="1" top="1" bottom="1"> <s:fill> <s:solidcolor id="bgFill" color="0xFFFFFF"> </s:solidcolor></s:fill> </s:rect> <s:scroller left="0" top="0" right="0" bottom="0" focusenabled="false" minviewportinset="1"> <s:datagroup id="dataGroup" itemrenderer="spark.skins.spark.DefaultItemRenderer"> <s:layout> <s:verticallayout gap="0" horizontalalign="contentJustify"> </s:verticallayout></s:layout> </s:datagroup> </s:scroller> </s:rectangulardropshadow></s:group> </s:popupanchor> <s:button id="openButton" width="20" right="0" top="0" bottom="0" focusenabled="false" skinclass="ComboBoxButtonSkin"> <mx:textinput id="inputField" textalign="left" left="0" right="19" top="0" bottom="0"> </mx:textinput></s:button></s:skin> \\ <fx:style> @namespace s "library://ns.adobe.com/flex/spark"; s|ComboBox s|TextInput { borderAlpha : .8; borderColor : #00FF00; } </fx:style> <s:combobox> ## Additional Implementation Details ---- _Enter implementation/design details for the feature here. This section may be updated after the spec signs off._ ## Prototype Work ---- There are two prototypes for ComboBox, one for highlighting the input string matching item and one for only showing the items that match the input string. ## Compiler Work ---- None ## Web Tier Compiler Impact ---- None ## Flex Feature Dependencies ---- None ## Backwards Compatibility ---- ### Syntax changes None ### Behavior None ### Warnings/Deprecation None ## Accessibility ---- ComboBox will need to be made accessible. It is a complex component with lots of user interactions and states. ## Performance ---- How expensive is it to filter or match to a large data set? Will filtering or matching work with virtualLayout? ## Globalization ---- None ## Localization ---- ### Compiler Features None ### Framework Features None ## Issues and Recommendations ---- ### Open Issues ### Resolved Issues _Should we proxy the TextInput properties?_ We can either expose the TextInput properties in ComboBox, or require the developer to set these properties directly on the TextInput in the ComboBox skin. The only properties I can see proxying are _restrict_ and _maxChars_. _Should we proxy the TextInput styles?_ Most of the TextInput styles are inheriting, so setting the styles on the ComboBox will be applied to the TextInput. For non-inheriting styles, should these just be set directly in the ComboBox skin? _Should we expose/redispatch TextInput events?_ TextInput dispatches _change_, _changing_, _enter_, and _selectionChange_. None of these events bubble, so they would have to be redispatched by the ComboBox. The _change_ and _changing_ events are already dispatched by ListBase, but have a different event type from the TextInput ones. Should we change the _change_ and _changing_ to _textChange_ and _textChanging_ events? The Halo ComboBox dispatches a _change_ event for both events. _Do we expose the TextInput.text as a property?_ We can add a property called _inputString_ which grabs the value from the TextInput's text property. The advantage of this property is that it makes it clear how to obtain the value (instead of having to go through the _textInput_ skin part. It also makes it easier to read and write to this value before the component has been initialized. The value will be locally stored until the textInput part is added). On the other hand, textInput is a public property and it should be fairly easy for developers to read/write from it granted they wait until the part has been added. _Should ComboBox subclass DropDownListBase or TextInput_ It will subclass DropDownListBase. There are far more properties and styles to support for DropDownListBase than TextInput. ComboBox reuses much of the functionality and implementation of DropDownListBase and its base classes. ## Documentation ---- _Describe any documentation issues or any tips for the doc team._ ## QA ---- _If there are testing tips for QA, note them here, include a link to the test plan document._ _TODO: update Flex Builder QA section._
[[ include ref='flexsdk_rightnav' ]]
[[ include ref='site:open_commentlogin' ]]
</s:combobox></int>

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.