Flex Developer. Flex Architect

The Nomadic Flex Developer

Flex Form & Function: Validators with Formatters in a Stateful Form

I’ve released a Flex project called Form & Function.

In a nutshell, what does it do?
Form & Function
reminds a user that their time-investment matters to you and your organization by giving the best possible experience when filling out a form.

In brief technical jargon, what does it do?
Form & Function creates the relationship between a validator, a formatter, and a restrictor for the most popular form types, and then notifies the developer and user about a form’s validity.

Who does it help?

  1. For developers, it simplifies building complex forms.
  2. For users, it helps them complete long forms.
  3. For project managers, it’s a milestone met.
  4. For user experience designers, it’s a starting place for a conversation.

Where can I find Form & Function?
The code base is hosted on code.google.com. Feel free to download the latest version of Form & Function from the Subversion trunk. Over the next few months, the project will be in a “Bleeding-Edge” release, and should not be considered backwards compatible from day-to-day.

What problems can Form & Function solve with my Flex Project?

Problem 1: The standard Flex Validators are too generic
Let’s start from the top and talk about the Adobe Flex validators. The types of validators Flex currently offers are:

  • CreditCardValidator
  • CurrencyValidator
  • DateValidator
  • EmailValidator
  • NumberValidator
  • PhoneNumberValidator
  • RegExpValidator
  • SocialSecurityValidator
  • StringValidator
  • Validator
  • ZipCodeValidator

Adobe gives you all the hooks you need to build your own validators using the Validator class and the RegExpValidator class (and both are used liberally with Form & Function).

The more specific validators, such as the CreditCardValidator, won’t validate credit-card security codes, only credit-card numbers). While a Merchant may not require the user enter a security code, the ability to validate against a security-code that’s tied into the card-type, should have been there all along, along with a CreditCardFormatter for user legibility.

Form & Function has validators that either improve upon, or plain-old, don’t exist in the latest Flex SDK.

Problem 2: Some Form Items require a linear Work Flow
Some form items require a linear workflow. For example, the mx:CreditCardValidator doesn’t force a linear workflow, because it’s left to the developer to implement a  workflow, most likey using States, but I prefer Convention over Configuration, and strongly prefer a consistent approach that 99% of developers are going to implement. In short: A user should be forced to select a card-type before he’s validating a credit-card-number (or the credit-card-security-code) against a null credit-card-type.

With your own application, I expect you may have similar workflow needs: The user shouldn’t be able to select one type of field until he’s selected another type of field, because there’s a dependency (maybe you have to load data for a “Region” only after the “Country” is selected).

Form & Function has ‘hooks’ on the FormItem level, as well as the Form level, to make implementing a linear workflow a relatively straight-forward process.

Problem 3: The Field restrictions aren’t implemented for popular Field-Types
When you use one of the Adobe Flex validators, you’ll notice there’s no association between the input-restrictions and the validation-routines. For example, a user should never be warned that the name of the event he’s posting exceeds the maximum length allowed. It’s better to just limit the number of characters he can enter, and if the name of the event has to be pretty short, give him a character countdown (4 more [characters] allowed…3 more [characters] allowed). A user is going to be pretty frustrated to see an error the developer let slide in the first place (“Why are you wasting my time letting me enter bad data? Just stop it from happening in the first place and let me finish my task so I can go back to doing something I actually enjoy!”).

If you have two views with the same field-type, Form & Function takes care of all the sub-classing for you, so you and the other developers know that the password field on your ‘Registration’ page has the exact same requirements as the password on your ‘Update Password’ page. I’ve seen many cases where developers may have re-used a validator, but they differed on the character restrictions, and the users couldn’t update their password once they registered because the ‘old’ password was invalid.

Form & Function restricts character limits and character types, using the most popular standards (and you can override these limitations to suit your own needs in a granular or global fashion). To add a password to your Form, you’ll only need to specify the type=”password”. That’s it. Form & Function takes care of the validation routines, the character restrictions and the maximum character limits.

Problem 4: The Flex Validators aren’t associated with the Flex Formatters
With the Adobe Flex forms, there is no association between the field-formatter and the field-validator. If the developer is going to require data-entered be in a specific format, the field-formatter’s value has to be the same as the format value of the field-validator. For example, if your phone formatter is formatting to (###) ###-#### and the validator is validating against (###) ### ####, problems for the developer, business and the user start to bubble up.

Form & Function tries to help the lack-of-association-problem by using a single touch point (the same format property) for the validator and formatter, and restricting characters that aren’t allowed as part of the format.

Problem 5: It’s not easy to know when a Form is Valid or Dirty
There is no simple approach to tracking an entire form’s validity. As a developer, you typically have to run a long operation to test the validity of each control, based on whether the field is, or isn’t, required, and add the error messaging. I’ve typically seen this done in an array of concatenated strings, and for a long form, the operation might be 100s of lines long.

Then, there’s the dirty-flag. A developer needs to know when the form is modified from the original state. If the form is different, you’re going to want save the data (either in intervals, or based on milestones) and only so many times.

Form & Function is going to help you by offering a built in validity checker and dirty flag handler for each form item that you specify is required.

Problem 6: The Long Form has disappeared (and users liked the Long Form)
I’ve worked primarily on large ‘transactional’ applications using Flex, and in most of our user-experience studies, we’ve found that users prefer one, long form to a wizard. Why? Well, for starters, the Flex Wizards actually made form entry more daunting, because the user doesn’t know how tedious the next form is going to be. Think of it like “Let’s Make a Deal”, where the contestant stands up and guesses correctly twice, and then he gets to door number 3 and can either quit and go home, or take the mystery prize. It could be a donkey, or it could be a new car. When you see a form longer than the one you just spent 10 minutes working on, you feel like you just won a the donkey. You worked through two challenges, and on the third challenge, you been slapped down.

Problem 7: The standard Flex Forms Layout isn’t easy to read
Users look at a form and they use visual reference points to determine what needs to be done. If the visual reference points aren’t there, users lose track of what they need to do next. Form & Function provides a symmetrical grid, so labels, controls, format hints and colors are consistent from line to line.

Problem 8: Users aren’t working against a milestone
So why not just build a long form? Well, to begin with, long-forms are harder to develop. You end up with one form that has to account for so much logic, with so many validators and formatters, that the code becomes unwieldy. Those same problems make a long-form hard to test and debug, too. Form & Functionencapsulates this logic, giving  you a simple tag-based approach to building a robust, long-form.

From a user-perspective, a long form needs to provide even more feedback about how far along the user is in the completion process, and what’s wrong as they go along. The user may have scrolled so far down the form after a few minutes that he never notices the “First Name” field is incomplete.

Form & Function also gives a visual hint within its own field-column. Basically, if a social security number has to be entered in a specific format, Form & Functionprovides an example that should be visually recognizable as an example. If you need to add more information, you can omit the example and replace it with a built-in “More Info” link. Consider the  “More Info” link as a very tiny help center for each field. The link either opens up a simple text file that you specify, or you can have Flash open a new HTML Window if you have considerably more information to specify.

More importantly, Form & Function is a Graphical Feedback Tool. It incorporates a Graphical Animated Feedback Indicator (GAFI), as well as form items that change their color based on their validity-state. So users are always aware which form items are valid, which are invalid, and which items haven’t had any interaction yet. And the GAFI keeps the user aware how many items he has left to complete.

For Adobe, and most companies for that matter, it would be hard to dictate all the field types for the various languages and locales used throughout the world. But I’m less concerned with an internationalized product, and more concerned with building something that ensures 50% of my user-base is going to complete the task at hand, and 100% are going to complete it with confidence. And for me, 99% of my user-base comes from the old US of A (and if you’re not using the project for the en_US locale, it’s easy to tailor it to suit your own needs).

  • What Does Form & Function Do for Users?
    • It helps them keep a sense of state. As users enter data in a field, the surrounding background color changes to reflect the form item’s validity.
    • Small visual clues hint to the necessary data format.
    • There’s a visual reward system. As users move along, a progress indicator gives the user a graphical and numeric indicator, letting them know how much more work they have to do before they’re done.
  • What Does Form & Function Do for Developers
    • It saves time. As a developer, you no longer have to write a validator, formatter, restrictor, character limits, dirty flag handlers, or multiple form item names.
    • It’s adopted Convention over Configuration. The accessing of data, the setting of data, and the field types are all straight forward. If you want to change the behavior, you can, but for the most part, everything is straight-forward, using the most conventional approach to development.
  • What types of fields does Form & Function support?
    1. Address 1
    2. Address 2
    3. Captcha
    4. CheckBox
    5. ComboBox
    6. American ExpressDiscoverDiner’s ClubVisaMasterCard
      • Credit Card Expiration Date
      • Credit Card Number
      • Credit Card Security Code
      • Credit Card Type
    7. Currency
    8. Date
    9. Email
    10. File Manager (including the previewing of image files)
    11. First Name
    12. Last Name
    13. Generic Input
    14. Numeric Stepper
    15. Password
    16. Phone Number
    17. Radio Button Group (confirming the user Selected 1 choice)
    18. Rich Text Editor
    19. Social Security
    20. Time
    21. Website
    22. Zip Code (with or without Extension)
  • How Can I customize Form & Function?
    1. Most methods that makes up the Base FormItem Class can be overridden. There’s also a generic input that allows you to specify generic string restraints & requirements. I’ll be working to add some interfaces to help you along for performing extensions, along with sample code.
    2. The styles are externalized so you can easily change the feedback colors, form-item colors, and more.
    3. The Graphical Animated Feedback Indicator (GAFI) is optional.

Download the latest version of Form & Function from Subversion

Can I try Form & Function?

Get Adobe Flash player

And the above is created with as little code as:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<?xml version="1.0" encoding="utf-8"?>
<mx:Application height="100%"
                width="100%"
                layout="absolute"
                xmlns:containers="org.davidbuhler.formandfunction.containers.*"
                xmlns:controls="org.davidbuhler.formandfunction.controls.*"
                xmlns:formandfunction="org.davidbuhler.formandfunction.*"
                xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:vo="org.davidbuhler.formandfunction.vo.*">

    <mx:Style source="/assets/styles/Styles.css"/>

    <formandfunction:BaseForm autoSaveEnabled="true"
                              autoSaveInterval="10000"
                              id="baseForm">

        <controls:FormHeader errorsCount="{baseForm.errorsCount}"
                             title="Form &amp; Function"/>

        <formandfunction:BaseFormItem id="email"
                                      required="true"
                                      type="email"/>

        <formandfunction:BaseFormItem id="password"
                                      required="true"
                                      type="password"/>

        <formandfunction:BaseFormItem id="radioButton"
                                      radioButtonList="{radioButtonList}"
                                      required="true"
                                      type="radioButtonGroup"/>

        <controls:BaseHRule/>

        <formandfunction:BaseFormItem formatHint="Jane's 5K Run"
                                      id="textInput"
                                      label="Event Name"
                                      maxLength="50"
                                      minLength="5"
                                      required="true"
                                      type="textInput"/>

        <formandfunction:BaseFormItem id="firstName"
                                      required="true"
                                      type="firstName"/>

        <formandfunction:BaseFormItem id="lastName"
                                      required="true"
                                      type="lastName"/>

        <formandfunction:BaseFormItem id="address1"
                                      required="true"
                                      type="address1"/>

        <formandfunction:BaseFormItem id="address2"
                                      required="true"
                                      type="address2"/>

        <formandfunction:BaseFormItem id="comboBox"
                                      label="State"
                                      required="true"
                                      type="comboBox"/>

        <formandfunction:BaseFormItem id="zipCode"
                                      required="true"
                                      type="zipCode"/>

        <formandfunction:BaseFormItem id="phoneNumber"
                                      required="true"
                                      type="phoneNumber"/>

        <formandfunction:BaseFormItem id="date"
                                      required="true"
                                      type="date"/>

        <formandfunction:BaseFormItem id="time"
                                      required="true"
                                      type="time"/>

        <formandfunction:BaseFormItem id="socialSecurity"
                                      required="true"
                                      type="socialSecurity"/>

        <controls:BaseHRule/>

        <formandfunction:BaseFormItem excludeDinersClub="true"
                                      id="creditCardType"
                                      required="true"
                                      type="creditCardType"
                                      whatsThisURL="Legal.html"/>

        <formandfunction:BaseFormItem id="creditCardNumber"
                                      required="true"
                                      type="creditCardNumber"/>

        <formandfunction:BaseFormItem id="creditCardSecurityCode"
                                      required="true"
                                      type="creditCardSecurityCode"/>

        <formandfunction:BaseFormItem id="creditCardExpirationDate"
                                      required="true"
                                      type="creditCardExpirationDate"/>

        <formandfunction:BaseFormItem id="numericStepper"
                                      required="true"
                                      type="numericStepper"/>

        <formandfunction:BaseFormItem id="currency"
                                      required="true"
                                      type="currency"/>

        <formandfunction:BaseFormItem id="uri"
                                      required="true"
                                      type="uri"/>

        <formandfunction:BaseFormItem id="checkBox"
                                      label="I agree"
                                      openLinksInNewWindow="true"
                                      required="true"
                                      type="checkBox"
                                      whatsThisURL="Sample.html"/>

        <formandfunction:BaseFormItem id="captcha"
                                      required="true"
                                      type="captcha"/>

        <formandfunction:BaseFormItem id="richTextEditor"
                                      label="Profile"
                                      required="true"
                                      type="richTextEditor"/>

        <containers:BaseControlBar width="100%">

            <controls:ClearButton enabled="{baseForm.isFormDirty}"/>

            <controls:SaveButton click="saveForm(event);"
                                 enabled="{baseForm.isFormDirty &amp;&amp; baseForm.isFormValid}"
                                 id="saveButton"
                                 label="{saveButton.enabled &amp;&amp; baseForm.autoSaveEnabled?'Save':baseForm.lastSavedLabel}"/>
        </containers:BaseControlBar>
    </formandfunction:BaseForm>

    <mx:Array id="checkBoxList">

        <vo:CheckBoxVO selected="true"
                       label="Large"/>

        <vo:CheckBoxVO label="Medium"/>

        <vo:CheckBoxVO selected="true"
                       label="Small"/>
    </mx:Array>

    <mx:Array id="radioButtonList">

        <vo:RadioButtonVO label="Male"/>

        <vo:RadioButtonVO label="Female"/>
    </mx:Array>

    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.events.FlexEvent;
            import org.davidbuhler.formandfunction.utils.Utils;

            private function saveForm(event:Event):void
            {
                mx.controls.Alert.show('Values: ' + baseForm.formValues);
            }
        ]]>
    </mx:Script>
</mx:Application>
Leave one

11 Responses

  1. Florian

     /  March 1, 2010

    Sounds cool from the description.

    However, looking at the google code rep, there is no application example.
    It would be cool to have some samples to see how it works (I guess you’re already working on it)

  2. Hi Florian,

    You can check out the zip here.

  3. Steve

     /  March 25, 2010

    Nice Work David.

    I noticed however that I couldn’t manage to tab between fields, or am I mistaken?

    Regards
    Steve

  4. Hi Steve,

    There’s a method called incrementTabIndex() inside of BaseFormItem.as. This method assigns a tabIndex to each control. If you mouse into the first field, you should be able to tab from field to field, thereafter. It’s possible this method has some issues that developed as the code-base evolved, but I know it worked at some point in development.

    Note: You need to use Javascript to set the cursor focus in the first field of a Flash Form when the HTML page loads the SWF form.

    If this doesn’t address the tab issue, let me know and I’ll look into the problem in more detail when I return from vacation.

  5. Steve

     /  March 26, 2010

    Hi David.

    Thanks, the problem was that the static variable was named tabIndex which was conflicting internally with tabIndex as tabIndex is a property of UIComponent; although you know al this anyway.

    So the fix is simple; rename the private static tabIndex definition in BaseFormItem to – private static var ctrlTabIndex:int
    AND inside incrementTabIndex – UIComponent(control).tabIndex=ctrlTabIndex++;

    regards, happy holidays
    Steve

  6. Hi David,

    I came here looking for a solution to validate data which is already coming from the database. The said data could have illegal characters like ampersands which I want to validate against. The restrict property of a TextInput only restricts the input of the illegal characters. Will this component be able to show validation errors on the data in the TextInputs once the Validator is run?

  7. Hi Jeffery,

    Ideally, you’d want to scrub the data coming back from the database by having an approved ‘whitelist’ of characters for each field type, and using Regular Expressions to replace any character that is not ‘approved’ in the response. Form & Function has a whitelist of characters for each field type that would give you a starting point to pursue this approach.

    However, if you have a legacy system that previously allowed bad characters, and you want to force the user to alter each field after the data is set from a server-side script, Form & Function can be tweaked to provide this functionality.

    Rather than go into details about the changes, I’ve uploaded a sample to demonstrate the changes necessary here.

    David Buhler

  8. I have implemented Steve’s tabIndex fix in the latest build.

  9. Keith Thompson

     /  May 13, 2010

    Thank you for this effort. I am adding more validators and adding functionality, all in Flex 4. Only minor changes required. It is a work in progess and so far I am only enhancing the “types” I need. If anyone is interested I can zip it up and email…

  10. Keith’s email: keith [ at ] sasimedia [dot] net

  11. @ Keith: If you’re interested in a new branch of the repository, I’m more than happy to add a new branch. Or if you wish to spin the code off into a separate project you host yourself, please feel free. This project may be under full-development again in the next few weeks, but the updated code-base would only support Flex 3.

Leave a Reply