Since creating a test case would be challenging I am posting the
component ValidatedComboBox.as. The problem I am having is that it
appears to call the keyDownHandler(event:KeyboardEvent):void function
twice for each keystroke. I have commented out most of that
function's code, as it used to handle all input there but now I only
handle the backspace there this is a patch to get it to function
somewhat.
package Classes.Input
{
import flash.events.Event;
import mx.controls.ComboBox;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.FocusEvent;
import flash.events.MouseEvent;
/**
* Create an extended version of the ComboBox that allows the
definition of invalid indexes.
*
* The developer defines one or more invalid indexes in a
comma separated list using the property badIndexes.
* Most commonly the developer would specify "0" which is the
first element in the list.
*
* New properties are;
* badIndexes - A string that allows the developer to define
a comma separated list of invalid indexes.
* isVald - A boolean that defines whether the field is valid.
*
* New Methods are;
* validateData() - This method checks if the data is valid
and returns true if valid, false if invalid.
*
*/
public class ValidatedComboBox extends ComboBox
{
/** Bad indexes - A comma separated list of invalid
indexes. */
private var _badIndexes:String = "";
/** Has this field passed validation */
private var _isValid:Boolean = true;
/** value */
private var _value:Object;
/** should we validate data */
private var _doValidateData:Boolean = true;
/** promptLabel */
private var _promptLabel:String;
/** toolTipField */
private var _toolTipField:String = "";
/** Default value A literal that represents the value
that will replace the "value"
* property when the method setDefault is executed */
private var _defaultValue:String = "";
private var _eventHandler:Function = this
["checkData"];
private var _typedText:String = "";
public function ValidatedComboBox()
{
//TODO: implement function
super();
this.addEventListener
(Event.CHANGE,_eventHandler)
}
/**
* Add a new inspectable property so the user can
enter the Bad Indexesn
* at authortime via the properties panel.
*
* @return the specified bad indexes
*/
[Inspectable( type="String" , defaultValue="" )]
public function get badIndexes():String
{
return this._badIndexes;
}
/**
* Sets the the specified bad indexes
*/
public function set badIndexes(
badIndexes:String ):void
{
this._badIndexes = badIndexes;
}
/**
* Add a new inspectable property so the user can
enter the promptLabel for the field
* at authortime via the properties panel.
*
* @return the specified promptLabel
*/
[Inspectable( type="String" , defaultValue="" )]
public function get promptLabel():String
{
return this._promptLabel;
}
/**
* Sets the the specified promptLabel
*/
public function set promptLabel(
promptLabel:String ):void
{
this._promptLabel = promptLabel;
}
/**
* Add a new inspectable property so the user can
specify the whether this field should be validated
* via the properties panel.
*
* @return the specified validate data flag.
*/
[Inspectable( type="Boolean" , defaultValue=false,
enumeration="true,false" )]
public function get doValidateData():Boolean
{
return this._doValidateData;
}
/**
* Sets the specified validate data flag.
*/
public function set doValidateData(
doValidateData:Boolean ):void
{
this._doValidateData = doValidateData;
}
/**
* Add a new inspectable property so the user can
enter the tool Tip Field for the field
* at authortime via the properties panel.
*
* @return the specified toolTipField
*/
[Inspectable( type="String" , defaultValue="" )]
public function get toolTipField():String
{
return this._toolTipField;
}
/**
* Sets the the specified toolTipField
*/
public function set toolTipField(
toolTipField:String ):void
{
this._toolTipField =toolTipField;
}
/**
* Add a new inspectable property so the user can
enter a Default value
* at authortime via the properties panel.
*
* @return the specified Maximum value
*/
[Inspectable( type="String" , defaultValue="" )]
public function get defaultValue():String
{
return this._defaultValue;
}
/**
* Sets the specified Default value
*/
public function set defaultValue(
defaultValue:String ):void
{
this._defaultValue = defaultValue;
var event:Event;
}
public function get isValid():Boolean
{
return _isValid;
}
override public function get value():Object
{
return _value;
}
public function set value(value:Object): void
{
this.selectedIndex = 0;
if (value != null)
{
setSelectedItem(value);
}
else
{
_value = "";
}
if (this.selectedIndex > -1)
{
_value = this.selectedItem["DATA"];
}
}
private function checkData(event:Event):void
{
if (this.selectedItem)
{
_value = this.selectedItem["DATA"];
validateData();
}
}
public function setDefault():void
{
this.value = _defaultValue;
}
public function validateData():Boolean
{
var aryTemp:Array = _badIndexes.split(",");
if (_doValidateData)
{
_isValid = ((aryTemp.indexOf
(this.selectedIndex.toString()) == -1) &&
(this.selectedIndex > -1));
trace("id=" + this.id + "|_isValid="
+ _isValid);
if (!_isValid)
{
this.errorString = '"' +
this.selectedLabel + '" is an invalid choice. ' +
this.selectedIndex.toString();
}
else
{
this.errorString = "";
}
}
return _isValid;
}
private function setSelectedItem
(strFindItem:Object):void
{
if (this.dataProvider != null)
{
this.selectedIndex = -1;
for (var
i:int=0;i<this.dataProvider.length;i++)
{
if (this.dataProvider[i].DATA
== strFindItem)
{
this.selectedIndex =
i;
break;
}
}
}
}
override protected function focusOutHandler
(event:FocusEvent):void
{
super.focusOutHandler(event);
_typedText = "";
validateData()
}
override protected function focusInHandler
(event:FocusEvent):void
{
super.focusInHandler(event);
_typedText = "";
}
override protected function textInput_changeHandler
(event:Event):void
{
_typedText += this.textInput.text;
if (!findFirstItem(_typedText))
{
_typedText = _typedText.substr
(0,_typedText.length -1);
findFirstItem(_typedText);
}
}
override protected function keyDownHandler
(event:KeyboardEvent):void
{
// trace("event="+event.toString());
// this.removeEventListener
(KeyboardEvent.KEY_DOWN,this.keyDownHandler);
event.preventDefault();
if(!event.ctrlKey)
{
if (event.keyCode ==
Keyboard.BACKSPACE || event.keyCode == Keyboard.DELETE)
{
_typedText = _typedText.substr
(0,_typedText.length -1);
findFirstItem(_typedText);
}
// if ((event.charCode > 31) &&
(event.charCode < 128))
// {
// _typedText +=
String.fromCharCode(event.charCode);
// }
// if (!findFirstItem(_typedText))
// {
// _typedText = _typedText.substr
(0,_typedText.length -1);
// }
}
// trace("_typedText=" + _typedText);
// this.addEventListener
(KeyboardEvent.KEY_DOWN,this.keyDownHandler);
// super.keyDownHandler(event);
}
private function findFirstItem
(strFindItem:String):Boolean
{
trace('strFindItem=' + strFindItem);
if (this.dataProvider != null)
{
if (strFindItem.length == 0)
{
this.selectedIndex = 0;
this.dropdown.selectedIndex =
0;
this.dropdown.scrollToIndex
(0);
_value = this.selectedItem
["DATA"];
return true;
}
this.dispatchEvent(new MouseEvent
("mouseOut"));
for (var
i:int=0;i<this.dataProvider.length;i++)
{
if (this.dataProvider[i]
[this.labelField].toString().substr(0,strFindItem.length).toUpperCase
() == strFindItem.toUpperCase())
{
this.selectedIndex =
i;
this.dropdown.selectedIndex = i;
this.dropdown.scrollToIndex(i);
_value =
this.selectedItem["DATA"];
if
(_toolTipField.length > 0)
{
this.toolTip
= this.dataProvider[i][_toolTipField]
this.dispatchEvent(new MouseEvent("mouseOver"));
}
return true;
}
}
}
return false;
}
}
}