Don’t you hate those web forms that ask for a phone number without telling you how you should enter it? You know, you enter 999 555-1212 and you get an error saying you should enter it as 9995551212. Or what about those forms that put the phone number into three fields but don’t automatically skip to the next field after you’ve completed a field?
Flex is partially guilty of this, too. You can put up a TextInput control to accept a phone number and associate a PhoneNumberValidator with it. The user can enter the number a variety of ways: 9995551212, (999) 555-1212, and 999 555-1212 are a few of the accepted ways. OK, that’s great but each person enters the number in a different way. And how is that stored in your database? Do you have code which normalizes all of the phone numbers? Or do you just plant it into the database in the way it was entered?
A masked input (called "pictures" in Cobol and PL/I) can help solve those problems. For example, suppose the user sees (___) ___-____ in an input field and then just types 9995551 but sees it being entered as (999) 555-1___, automatically skipping over the parentheses and hypen. Wouldn’t that be great? And suppose you can extract the value either as 9995551212 or (999) 555-1212 and store the values consistently in your database?
I’ve created a new Flex 2 component which does this by extending the TextInput control and capturing the keystrokes. The component is called MaskedTextInput and here is how it works.
You can download the zip file containing the control and a sample application by clicking here.
Creating this control was not that difficult. You need to intercept some keystrokes and compare them to a masking pattern. For the masks, I used # to indicate a numeric-only position; C to indicate an alphabetic that would automatically get capitalized; c to indicate an alphabetic that would automatically get folded to lowercase, and A (or a) to indicate any character. So a phone number mask can be "(###) ###-####" and a first name field can be "Ccccccccccc". You can take this code and expand on these if you like.
The tricky parts were handling Backspace, Space, Delete, Home, End, and the left and right arrow keys. To make things simple I did not allow for insertion, just overwriting. That is, if you have (999) 555-____ and you reposition the insertion point before the first 5 and then press the 6 key, the 6 is not inserted but rather replaces the 5 so you wind up with (999) 655-____ with the insertion point now after the 6.
The new control has the following properties:
inputMask: This is the mask to use, such as the phone number mask above or ###-##-#### for a US Social Security number.
blankChar: This is the character to display in the text field in place of the mask characters. In other words, the phone number appears a (___) ___-____ with the default blankChar as underscore.
defaultChar: This character is substituted for the blankChar when the text is retrieved from the control using the actualText property. For example, if you want to make sure that any # is retrieved as a zero, make the defaultChar a 0. This character is also used when the Space bar is pressed.
text: The TextInput text property is overridden to make it easier to set and get the text from the control. For example, if you have the phone input mask you can set the data as text="9995551212" and the characters will be divided out according to the inputMask and show up as "(999) 555-1212" in the control. When you use the text property to get the text, the raw data is returned, without mask or blankChar characters.
The new control also has the following event:
inputMaskEnd: This event is dispatched when the last character of the mask has been entered. You can use this to skip to the next field. If you have a Form that is made up of many MaskInput controls, this event coupled, with the code to skip to the next field, would allow users to quickly enter form data, automatically skipping from field to field.
As with most Flex 2 components, a key function that is overridden is updateDisplayList(). This function is called whenever the display should change. You might, for example, draw the background or if the component is a skin, draw the border. Flags are often used to indicate what has changed so not everything is drawn or changed each time updateDisplayList is called. For MaskedInput, updateDisplayList does three things, all dictated by flags.
If the inputMask is changed, an internal working array which is filled as the user types, has to be changed. If the text property changes it is copied into the working buffer. Finally, if the working buffer changes because the user has entered characters, the display has to be refreshed.
Keep in mind that when writing components for Flex 2, most of the work is done in or called by updateDisplayList. The other functions are generally used to set up the conditions and values for updateDisplayList to do its job.