Chapter 15. Validating and Formatting Data

When working with data, you’ll frequently need to ensure that the data adheres to certain rules. When the data is from user input, this is called validation. When the data is being displayed or needs to be in a particular form before storing it or sending it to a service method, this is called formatting. The Flex framework provides mechanisms for both of these types of operations. In this chapter, we will look at both validating and formatting data.

Validating User Input

When you work with user input, you frequently may want to validate that input before submitting it for some sort of course of action, either client-side or server-side. For example, if you want to submit form data to a server script that inserts the data to a database, you may need to verify that the values are in the correct format so that you can insert them (e.g., a numeric value needs to be a number and a date needs to be formatted in a way that your script can parse it into the format you require for the database). Often it is advisable to add both client-side and server-side validation. The server-side validation ensures that no strange or incorrect values were inserted at the time the request was made, and the client-side validation makes sure the data is valid before even making a request. Only client-side validation is within the scope of Flex coding, and therefore we will look at how to validate data client-side using Flex.

You can write your own validation procedures for this purpose. Yet most validations require rewriting the same basic code time after time. All that redundancy leads to a lot of time spent rewriting the same basic code rather than focusing on new tasks. For this reason, the Flex framework ships with a type of component called a validator, which you can use to assist with validating user input. There are a handful of standard validator types, including StringValidator, NumberValidator, DateValidator, PhoneValidator, and ZipCodeValidator. The next few sections discuss how to work with each of the standard validators and show you how to build custom validator types.

Using Validators

There are two ways you can work with validators: with MXML or with ActionScript. For many use cases, MXML is sufficient for your validation needs. Although it is common to work with validators in MXML, there are many cases in which you’ll work with validators both in MXML and in ActionScript for the same project—creating the validators using MXML, and adding extra functionality with ActionScript. In a few cases, you’ll work with validators entirely in ActionScript. Those are special cases in which you need to be able to build the validators dynamically at runtime because the exact user input controls and validation needs are not known at compile time.

Validator basics

All validator types inherit from a base type called mx.validators.Validator. Although you’ll work with subtypes more frequently (e.g., StringValidator), you can work with Validator for very basic validation requirements, and all the validator types inherit the basic functionality and properties of the Validator type.

When you create a validator, you must specify at least two properties, called source and property. The source is a reference to the object containing the data you want to validate, and the property is the property of that object that contains the data. You can create a validator using MXML using the following structure:

<mx:Validator source="{sourceObject}" property="sourceProperty" />

By default, the behavior of a validator is simply to validate that the user has specified a value. All validators have a property called required that defaults to true. The following achieves exactly the same thing as the preceding code example:

<mx:Validator source="{sourceObject}" property="sourceProperty" required="true" />

The default trigger for a validator is a valueCommit event. All input controls dispatch valueCommit events when the value is changed programmatically, or when the focus shifts away from the control. Example 15-1 illustrates a very basic validator use. The application consists of a form with a text input and a button. The validator uses the text input as the source, and it validates that the user has input at least one character. The validator runs when the user moves focus away from the text input. That means you must first move focus to the text input (by clicking in it) and then shift focus away either by clicking on the button or by pressing the Tab key.

Example 15-1. Basic form validation

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit"/>
        </mx:FormItem>
    </mx:Form>

    <mx:Validator source="{username}" property="text" />

</mx:Application>

When a validator runs, there are two possible outcomes: either it will validate the data successfully or it won’t. If it validates the data, the default behavior is to do nothing. If it does not successfully validate the data, the default behavior for a validator is to apply a red outline to the input control and display a message when the user moves the mouse over the control.

As mentioned earlier, it is more common to create validators using MXML than ActionScript. Yet there are valid use cases that require you to create the validators using ActionScript. For example, if you create a form at runtime based on XML data, you must also create the validators at runtime, and that requires ActionScript. To create a validator at runtime, use a standard new statement with the constructor for the validator type. For example, the following creates a Validator object:

_validator = new Validator();

You must always set both the source and the property properties as well:

_validator.source = sourceObject;
_validator.property = "sourceProperty";

Example 15-2 achieves exactly the same thing as Example 15-1, but in this case, the validator is created using ActionScript.

Example 15-2. ActionScript-based validator

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
initialize="initializeHandler(event)">
    <mx:Script>
        <![CDATA[
            import mx.validators.Validator;

            private var _validator:Validator;

            private function initializeHandler(event:Event):void {
                _validator = new Validator();
                _validator.source = username;
                _validator.property = "text";
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit"/>
        </mx:FormItem>
    </mx:Form>

</mx:Application>

Unless stated otherwise, properties of validators are set using MXML or ActionScript.

Customizing validator messages

When a validator runs and fails to successfully validate the data, it displays a message by default. The message type depends on the type of validator as well as the way in which the validator failed. The Validator class defines just one type of message that appears when a required field contains no data. The default message is “This field is required.” That message may be appropriate in most cases, but if your application requires a custom message, you can change the value using the requiredFieldError property:

<mx:Validator source="{sourceObject}" property="sourceProperty"
requiredFieldError="Hey, fill out this item" />

All validator types inherit the required and requiredFieldError properties, and so you can set a custom requiredFieldError message for any validator type. However, many validator types may fail for reasons other than the field simply being required. For example, a PhoneNumberValidator can fail if the data contains an invalid character. Each validator type also defines properties allowing you to customize the error messages for each type of possible error. For example, the following customizes the error message when the user specifies an invalid character for a phone number:

<mx:PhoneNumberValidator source="{sourceObject}" property="sourceProperty"
    invalidCharError="You really ought to use the proper characters" />

We’ll look at all the possible errors for each validator type later in this chapter.

Handling validator events

Validators dispatch two basic types of events: valid and invalid. When a validator runs successfully, it dispatches a valid event; when it doesn’t, it dispatches an invalid event. By default, the source control receives and handles the events. All input controls are configured to respond to valid and invalid events, typically by applying a red outline and displaying a message. For this reason, it’s not a necessity that you explicitly handle the validator events. However, if you want to modify the default behavior, you’ll need to listen for and handle the validator events.

You can handle the events in one of two ways.

  • Specify values for the valid and invalid attributes of the MXML tag used to create the validator:

    <mx:Validator source="{sourceObject}" property="sourceProperty"
        valid="validHandler(event)" invalid="invalidHandler(event)" />
  • Use addEventListener() to register listeners for the events via ActionScript. Use the mx.events.ValidationResultEvent.VALID and the mx.events.ValidationResultEvent.INVALID constants:

    validator.addEventListener(ValidationResultEvent.VALID, validHandler);
    validator.addEventListener(ValidationResultEvent.INVALID, invalidHandler);

Example 15-3 handles the valid and invalid events such that in addition to the default behavior, the form item label also changes.

Example 15-3. Handling validator events

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            import mx.events.ValidationResultEvent;

            private function invalidHandler(event:ValidationResultEvent):void {
                usernameItem.setStyle("color", 0xFF0000);
                usernameItem.label = "*Name";
            }

            private function validHandler(event:ValidationResultEvent):void {
                usernameItem.setStyle("color", 0x000000);
                usernameItem.label = "Name";
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text"
invalid="invalidHandler(event)" valid="validHandler(event)" />

</mx:Application>

Every validator can have a listener that is automatically configured to listen to validator events. By default, the listener is the source object. As mentioned, all user input controls are able to listen for the validator events and respond to them in a default manner. If you want to specify a different, nondefault listener for a validator, you can use the listener property to assign a reference to a new object. The listener object must be an object that implements the IValidatorListener interface. The UIComponent class implements IValidatorListener, so you can assign any UIComponent instance (including any user input control) as the listener. Although slightly convoluted, the following example illustrates how the listener property can work. In this example, the validator is applied to a data model rather than a control. The data model value is assigned via data binding from a text input:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Model id="userData">
        <userData>
            <username></username>
        </userData>
    </mx:Model>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Binding source="username.text" destination="userData.username" />

    <mx:Validator id="validator" source="{userData}" property="username" />

</mx:Application>

Although the validator is applied to the data model field, it does not actually do anything useful. This is for two reasons, the first of which is that the normal trigger for the validator won’t work because data models don’t dispatch valueCommit events. We’ll talk more about alternative ways of triggering validators in the next section, but for now you can simply define the validator’s trigger property so that it’s a reference to the input control. That tells the validator to listen for valueCommit events from the input control rather than the data model:

<mx:Validator id="validator" source="{userData}" property="username"
    trigger="{username}" />

However, even with the preceding change, the application won’t display any sort of notification when the validation fails. That’s due to the second reason, which is that a validator’s default listener is the source object, which is a data model in this case. However, a data model does not know how to handle those events. Instead, if you want a listener object to handle the events, you must override the default listener value by setting the listener property for the validator. With the following change to the validator, it uses the input control as the listener:

<mx:Validator id="validator" source="{userData}" property="username"
    trigger="{username}" listener="{username}" />

This example isn’t very practical, though. There is no reason in this case for you to validate data in a data model rather than in the text input. However, it does illustrate the basics of how a listener works. Now let’s look at two more useful examples, the first of which is extremely simple.

As you saw earlier in this section, you can explicitly handle valid and invalid events. However, when doing so, you might have noticed that the default listener behavior (the red outline and message applied to the source control) is still applied. If you want to use explicit event handlers for the valid and invalid events without the default listener behavior, you must override the default listener setting by using a value of an empty object. You can use the {} literal notation to create an object, or you can use the Object constructor as part of a new statement. Example 15-4 uses an empty object for the listener along with explicit event handlers. In this example, the label changes when validator events occur, but the default listener behavior does not. As already stated, by default validators will display outlines around components with invalid values. However, in this example, we’re short-circuiting the default behavior.

Example 15-4. Overriding default validator behavior

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[

            import mx.events.ValidationResultEvent;

            private function invalidHandler(event:ValidationResultEvent):void {
                usernameItem.setStyle("color", 0xFF0000);
                usernameItem.label = "*Name";
            }

            private function validHandler(event:ValidationResultEvent):void {
                usernameItem.setStyle("color", 0x000000);
                usernameItem.label = "Name";
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text"
invalid="invalidHandler(event)" valid="validHandler(event)"
listener="{new Object()}" />

</mx:Application>

You can also assign a non-default listener when you want to use a customized listener. The customized listener might do any number of things, such as auto-correcting a value. To register a custom listener, the class must implement the mx.validators.IValidatorListener interface, which requires public properties (or getters/setters) called errorString and validationSubField as well as a public method called validationResultHandler(), which accepts a parameter of type mx.events.ValidationResultEvent. Example 15-5 is an example of a simple class that implements the interface. This class allows you to pass it any control with a text property, and it attempts to auto-correct the field. In this example, the auto-correction is very limited in scope: it auto-corrects only the string abc and makes it abcd.

Example 15-5. Customized validator listener (AutoCorrectTextListener.as)

package com.oreilly.programmingflex.validation.listeners {

    import mx.events.ValidationResultEvent;
    import mx.validators.IValidatorListener;
    import mx.core.UIComponent;

    public class AutoCorrectTextListener implements IValidatorListener {

        private var _errorString:String;
        private var _validationSubField:String;
        private var _control:Object;
        private var _passThroughEvent:Boolean;

        // Implement the errorString and validationSubField getters and setters.
        // They simply act as accessor methods for corresponding private properties.
        public function get errorString():String {
            return _errorString;
        }

        public function set errorString(value:String):void {
            _errorString = value;
        }

        public function get validationSubField():String {
            return _validationSubField;
        }

        public function set validationSubField(value:String):void {
            _validationSubField = value;
        }

        // The constructor accepts two parameters: the control with a text
        // property you want to target, and an optional parameter specifying
        // whether or not to pass through the event to the control if it
        // cannot auto-correct.
        public function AutoCorrectTextListener(control:Object,
                                                passThroughEvent:Boolean = true) {
            _control = control;
            _passThroughEvent = passThroughEvent;
        }

        // This method gets called when the validator dispatches an event. The code
        // auto-corrects the text if possible (in this case it only auto-corrects
        // one case). If it cannot auto-correct, it passes the event (if
        // applicable) to the control.
        public function validationResultHandler(event:ValidationResultEvent):void {
            if(_control.text == "abc" || _control.text == "abcd") {
                _control.text = "abcd";
            }
            else {
                if(_passThroughEvent) {
                    _control.validationResultHandler(event);
                }
            }
        }

    }
}

The MXML in Example 15-6 uses this custom listener.

Example 15-6. Using a customized validator listener

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
initialize="initializeHandler(event)">
    <mx:Script>
        <![CDATA[

            import com.oreilly.programmingflex.validation.listeners.
AutoCorrectTextListener;

            private var _listener:AutoCorrectTextListener;

            private function initializeHandler(event:Event):void {

                // Create a new listener that targets the text input control.
                _listener = new AutoCorrectTextListener(username);

                // Register the listener with the validator. The validator is
                // created via MXML later in the document. The MXML id attribute
                // is set to validator, which is the reason you can reference the
                // object by that name here.
                validator.listener = _listener;
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text" />

</mx:Application>

When you test this application, you can try using any text other than abc or abcd, and the event will be passed to the control with the standard behavior following it. If you use the text abc, it auto-corrects to abcd.

Triggering validators

To run, a validator must first be triggered. As you’ve already seen, the default trigger for a validator is the valueCommit event, which is dispatched by the source object. In many cases, that is appropriate because the valueCommit event occurs for all input controls when the value is set programmatically or when the focus shifts from the control. However, there are reasons you may want to change the default trigger for a validator. For example, although the most common use case for validators is to use a user input control as the source, you could theoretically use any object and any property. If the object type you use as the source does not dispatch a valueCommit event, the default trigger will never occur. Another, more common scenario for changing the default trigger is one in which you want a different object to trigger the validator. For example, rather than triggering a validator when the user moves focus from a text input, you might want to trigger the validator when the user clicks on a button.

The two properties you can use with a validator to change the trigger are trigger and triggerEvent. The trigger property requires a reference to an object (which must be an event dispatcher) that you want to use as the trigger. The triggerEvent property requires the name of the event you want to use to trigger the validator. The following example uses the click event for the button to trigger the validator:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator source="{username}" property="text" trigger="{button}"
        triggerEvent="click" />

</mx:Application>

You can have even further control over how and when validators run by using ActionScript to run the validators. All validators have a validate() method that you can call to run the validator. If you want to call the validate() method for a validator, you must ensure that the object can be referenced via ActionScript, regardless of whether you set the id property when creating the validator via MXML or you assign the validator to a variable when creating it with ActionScript. The following example sets the trigger property of a validator to a new EventDispatcher object so that the default trigger does not work:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text"
        trigger="{new EventDispatcher()}" />

</mx:Application>

If you were to test the preceding code, you’d find that the validator does not run automatically because the trigger is a new EventDispatcher object. Now you can add an event listener to the button so that it calls a function when clicked by the user. The validate() method of the validator can be called with the function, as shown here:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Script>
        <![CDATA[

            private function runValidator(event:MouseEvent):void {
                validator.validate();
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" click="runValidator(event)" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text"
        trigger="{new EventDispatcher()}" />

</mx:Application>

If you wanted to achieve the same result as with the standard trigger, it is far simpler to use the default behavior rather than writing all the extra code (as in the preceding example). However, the validate() method allows you greater control over how the application behaves.

The validate() method not only runs the validator, but it also returns a ValidationResultEvent object, which tells you whether the validation succeeded. The type property of the object is either valid or invalid (for which you can use the ValidationResultEvent.VALID and ValidationResultEvent.INVALID constants, respectively). Example 15-7 uses validate() to display an alert when the user clicks on the button but doesn’t properly fill in a required field.

Note

Note that in this example we’re calling validate() with two optional parameters. The first parameter specifies the value to validate. A value of null indicates to use the default value, which is retrieved from the source of the validator. The second parameter indicates whether or not to suppress validation events.

Example 15-7. Running validation with ActionScript

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.events.ValidationResultEvent;
            import mx.controls.Alert;

            private function runValidators(event:Event):void {
                // Run the validate() method and assign the result to a variable.
                var validationResultEvent:ValidationResultEvent =
validator.validate(null, true);
                // If the result of the validate() method call is invalid then
                // display an alert.
                if(validationResultEvent.type == ValidationResultEvent.INVALID) {
                    Alert.show("You must specify a value");
                }
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" click="runValidators(event)" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="validator" source="{username}" property="text"
        trigger="{null}" />

</mx:Application>

When you’re working with more than one validator and you want to call the validate() method of each, you can explicitly call the method of each, or you can use a static Validator class method, called validateAll(). The validateAll() method requires an array parameter for which every element is a validator object. The validateAll() method then returns an array with all the ValidationResultEvent objects for every validator that returned an invalid response. If all the validations passed, the return array is empty. Example 15-8 uses four validators (each of these are standard validator types discussed in more detail in the next section). When the user clicks the button, the button dispatches an event that calls a function that runs validateAll(), and it displays an alert notifying the user if any of the fields did not validate properly.

Example 15-8. Using validateAll()

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
initialize="initializeHandler(event)">
    <mx:Script>
        <![CDATA[
            import mx.events.ValidationResultEvent;
            import mx.controls.Alert;
            import mx.validators.Validator;

            private var _validators:Array;

            private function initializeHandler(event:Event):void {
                // Create an array with the validators.
                _validators = [usernameValidator, phoneValidator, emailValidator,
zipCodeValidator];
            }

            private function runValidators(event:Event):void {
                // Run all the validators.
                var results:Array = Validator.validateAll(_validators);
                // If the results array is empty then everything passed. If it's not
                // empty then at least one validator didn't pass.
                if(results.length > 0) {
                    var message:String = "The following fields are incorrect:
";

                    // Loop through all the results, and retrieve the id of the
                    // source for the corresponding validator.
                    for(var i:uint = 0; i < results.length; i++) {
                        message += results[i].target.source.id + "
";
                    }
                    Alert.show(message);
                }
            }

        ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem id="usernameItem" label="Name">
            <mx:TextInput id="username"/>
        </mx:FormItem>
        <mx:FormItem label="Phone">
            <mx:TextInput id="phone"/>
        </mx:FormItem>
        <mx:FormItem label="Email">
            <mx:TextInput id="email"/>
        </mx:FormItem>
        <mx:FormItem label="Zip Code">
            <mx:TextInput id="zipcode"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit" click="runValidators(event)" />
        </mx:FormItem>
    </mx:Form>

    <mx:Validator id="usernameValidator" source="{username}" property="text" />
    <mx:PhoneNumberValidator id="phoneValidator" source="{phone}" property="text" />
    <mx:EmailValidator id="emailValidator" source="{email}" property="text" />
    <mx:ZipCodeValidator id="zipCodeValidator" source="{zipcode}" property="text" />

</mx:Application>

Using Standard Framework Validators

The Flex framework includes not only the base validator, Validator, but also many validators for common sorts of data formats. The framework ships with the following validators:

  • StringValidator

  • NumberValidator

  • DateValidator

  • EmailValidator

  • PhoneNumberValidator

  • ZipCodeValidator

  • CreditCardValidator

  • CurrencyValidator

  • SocialSecurityValidator

  • RegExpValidator

All the validator types are subtypes of Validator, and they inherit all the same properties and methods. But each of these subtypes implements specialized validation behaviors. We discuss each of these validator types in greater detail in the next few sections.

StringValidator

The StringValidator allows you to verify that a string value length is within a specific range. You can define minLength and maxLength property values for StringValidators, as in the following example:

<mx:StringValidator source="{sourceObject}" property="sourceProperty"
    minLength="5" maxLength="10" />

You can also specify custom error messages, just in case the validation fails, using the tooShortError and tooLongError properties. These error messages are displayed when the value length is less than the minLength and greater than the maxLength, respectively.

<mx:StringValidator source="{sourceObject}" property="sourceProperty"
    minLength="5" maxLength="10" tooShortError="You gotta use a
longer number, buddy" tooLongError="Whoa! Shorter numbers, please" />

NumberValidator

The NumberValidator allows you to validate all sorts of number values. You can specify a range of allowable values using the minValue and maxValue properties:

<mx:NumberValidator source="{sourceObject}" property="sourceProperty"
    minValue="-5" maxValue="5" />

The default value for minValue and maxValue is NaN (not a number), which means that no limit is placed on the range. If you set a value for either property and you later want to remove the limit, just assign a value of NaN to the validator, as shown here:

numberValidator.minValue = NaN;

If you want to allow or disallow negative numbers, you can use the allowNegative property. The default value is true, but setting it to false disallows use of negative numbers:

<mx:NumberValidator source="{sourceObject}" property="sourceProperty"
    allowNegative="false" />

By default, a NumberValidator allows any number type, but you can explicitly specify whether you want to accept all number types (real) or just integers (int) using the domain property. The default value is real, but the following example allows only integers:

<mx:NumberValidator source="{sourceObject}" property="sourceProperty"
    domain="int" />

When allowing real numbers you can also control the allowable precision. The precision is the measure of the number of decimal places. The precision property controls this setting, and it has a default value of −1, which allows all precisions. A value of 0 effectively accomplishes the same thing as setting domain to int (meaning all values must be integers). Positive integer values for precision limit the number of allowable decimal places. The following allows up to only four decimal places:

<mx:NumberValidator source="{sourceObject}" property="sourceProperty"
    precision="4" />

By default, a NumberValidator validates using the thousands place marker and decimal marker characters used in the United States: the comma for thousands and the dot for a decimal place. However, if you need to validate using different marker characters, you can specify those values using the thousandsSeparator and decimalSeparator properties, respectively. The only rules for these properties are that they must not be digits and they cannot each have the same value. The following example uses the characters used by many European countries:

<mx:NumberValidator source="{sourceObject}" property="sourceProperty"
    thousandsSeparator="." decimalSeparator="," />

You can also specify many custom errors using the properties of a NumberValidator, including the following: decimalPointCountError, exceedsMaxError, integerError, invalidCharError, invalidFormatCharsError, lowerThanMinError, negativeError, precisionError, and separationError. Each of these properties is documented at http://livedocs.macromedia.com/flex/3/langref/mx/validators/NumberValidator.html.

DateValidator

DateValidator allows you to validate values as dates. There are several basic properties you can configure to customize this type of validator, and there are advanced properties that allow you to use the validator with several inputs at once.

The basic properties you can use with a DateValidator are allowedFormatChars and inputFormat. The allowedFormatChars property allows you to specify which characters are allowable as delimiters between year, month, and date. The default value is /-., which means any of the following are valid:

1/20/2010
1 20 2010
1.20.2010
1-20-2010
1202010

The following allows only the asterisk character as a delimiter:

<mx:DateValidator source="{sourceObject}" property="sourceProperty"
    allowedFormatChars="*" />

The inputFormat property determines the order of the year, month, and date parts. You can use the strings YYYY, MM, and DD to represent each of those parts. You can use any of the default delimiter characters as delimiters in the inputFormat string. The default value is MM/DD/YYYY. The following example requires that the date appear with the year followed by the month followed by the date:

<mx:DateValidator source="{sourceObject}" property="sourceProperty"
    inputFormat="YYYY/MM/DD" />

Unlike most of the validators, the DateValidator allows you to use one validator to validate more than one input. This is because date inputs frequently may span three inputs: one for the year, one for the month, and one for the date. When you specify a source property value for a DateValidator, it assumes you want to validate just one input. However, you have the option to specify three different sources and properties using the yearSource, monthSource, daySource, yearProperty, monthProperty, and dayProperty properties:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:HBox>
        <mx:VBox>
            <mx:TextInput id="year" width="40" />
            <mx:Label text="Year" />
        </mx:VBox>
        <mx:VBox>
            <mx:TextInput id="month" width="40" />
            <mx:Label text="Month" />
        </mx:VBox>
        <mx:VBox>
            <mx:TextInput id="day" width="40" />
            <mx:Label text="Day" />
        </mx:VBox>
        <mx:Button click="trace(validator.validate())" label="Validate" />
    </mx:HBox>
    <mx:DateValidator id="validator" yearSource="{year}" yearProperty="text"
        monthSource="{month}" monthProperty="text" daySource="{day}"
        dayProperty="text" inputFormat="YYYY/MM/DD" />

</mx:Application>

EmailValidator

The EmailValidator is easy to implement, as it doesn’t require any additional properties aside from the standard source and property. It simply validates the source value as a valid email address:

<mx:EmailValidator source="{sourceObject}" property="sourceProperty" />

PhoneNumberValidator

The PhoneNumberValidator lets you validate that a value is in a valid format for a phone number. According to the PhoneNumberValidator rules, a valid phone number consists of at least 10 numeric characters as well as possible additional formatting characters. You can use just one property to customize the rules a PhoneNumberValidator uses. The allowedFormatChars property lets you specify the valid non-numeric characters that are allowable in a phone number value. The default set of allowable characters consists of (, ), , ., +, and a space. The following code allows for phone number values in which the only valid formatting characters are dots:

<mx:PhoneNumberValidator source="{sourceObject}" property="sourceProperty"
    allowedFormatChars="." />

ZipCodeValidator

The ZipCodeValidator validates that the value is in the format of a valid U.S. zip code or a Canadian postal code. You can specify what type of code it validates using the domain property. The default value is set to the ZipCodeValidatorDomainType.US_ONLY value, which means the validator won’t validate Canadian-style postal codes. Optionally, you can use the ZipCodeValidatorDomainType.US_OR_CANADA constant to recognize Canadian postal codes, as shown here:

<mx:ZipCodeValidator source="{sourceObject}"
property="sourceProperty" domain="{ZipCodeValidatorDomainType.US_OR_CANADA}" />

You can also use the allowedFormatChars property to specify a set of allowable formatting characters consisting of nonalphanumeric characters; the default set consists of a space or a hyphen (-).

CreditCardValidator

The CreditCardValidator allows you to validate that a number is in the proper format and follows the basic rules for credit card numbers. Although it cannot verify that the number is a valid credit card number, it can provide a simple test to ensure that no user error caused an incorrect number of digits or the wrong prefix for a card type. The CreditCardValidator can test for American Express, Diners Club, Discover, MasterCard, and Visa number formats. This validator type requires two input sources: one for the card type (usually a radio button group or a combo box) and one for the card number (usually a text input). Here’s an example:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:VBox>
        <mx:ComboBox id="cardType">
            <mx:dataProvider>
                <mx:ArrayCollection>
                    <mx:Array>
                        <mx:String>American Express</mx:String>
                        <mx:String>Diners Club</mx:String>
                        <mx:String>Discover</mx:String>
                        <mx:String>MasterCard</mx:String>
                        <mx:String>Visa</mx:String>
                    </mx:Array>
                </mx:ArrayCollection>
            </mx:dataProvider>
        </mx:ComboBox>
        <mx:TextInput id="cardNumber" />
        <mx:Button click="trace(validator.validate())" label="Validate" />
    </mx:VBox>
    <mx:CreditCardValidator id="validator" cardNumberSource="{cardNumber}"
cardNumberProperty="text" cardTypeSource="{cardType}" cardTypeProperty="value" />

</mx:Application>

CurrencyValidator

The CurrencyValidator validates currency values, such as dollar amounts. Obviously, currency formatting and numeric formatting have much in common, and for that reason there are many similarities between CurrencyValidator and NumberValidator. For example, CurrencyValidator’s minValue, maxValue, precision, allowNegative, decimalSeparator, and thousandsSeparator properties work exactly as they do for a NumberValidator. In addition, a CurrencyValidator lets you specify currencySymbol and alignSymbol properties. The default value for currencySymbol is the U.S. dollar sign ($). You can use the alignSymbol property to specify where the currency symbol must appear relative to the numeric value. The valid values are CurrencyValidatorAlignSymbol.LEFT, CurrencyValidatorAlignSymbol.RIGHT, and CurrencyValidatorAlignSymbol.ANY. CurrencyValidatorAlignSymbol.LEFT is the default value.

SocialSecurityValidator

The SocialSecurityValidator validates a value that adheres to the rules for a U.S. Social Security number (###-##-####). This validator allows you to customize the validation rules by specifying the allowable formatting characters via the allowedFormatChars property; the default value is a space or a hyphen (-).

RegExpValidator

The RegExpValidator allows you to use regular expressions to validate values. You can use the RegExpValidator for any type of validation that isn’t covered by the other standard validators. The RegExpValidator requires that you set at least one property, expression, which is the regular expression you want to use to validate the data. In addition, you can optionally specify a value for the flags property, which can use any combination of the valid regular expression flags: i, g, m, s, and x.

Note

You can read more about the use of regular expressions in Flex 3 at http://livedocs.adobe.com/flex/3/html/help.html?content=12_Using_Regular_Expressions_03.html

The following example validates a text area to ensure that it contains at least 5 words:

<mx:RegExpValidator expression="(w+W*){5,}" flags="ig"
    source="{comments}" property="text" />

Writing Custom Validators

If one of the standard validators doesn’t run the sort of validation you require, you can write a custom validator. To write a custom validator, you must write an ActionScript class that extends mx.validators.Validator, and the class must override the doValidation() method. The doValidation() method is protected; it requires an Object parameter and returns an array. If the validation does not succeed, the method returns an array of ValidationResult objects. If the validation does succeed, the method returns an empty array. The WordCountValidator in Example 15-9 is a simple example that validates a value based on minimum word count.

Example 15-9. Custom validator

package com.oreilly.programmingflex.validators {

    import mx.validators.Validator;
    import mx.validators.ValidationResult;

    public class WordCountValidator extends Validator {

        private var _count:int;

        public function get count():int {
            return _count;
        }

        public function set count(value:int):void {
            _count = value;
        }

        public function WordCountValidator() {
            super();
            _count = −1;
        }

        override protected function doValidation(value:Object):Array {
            var results:Array = new Array();
            results = super.doValidation(value);
            if(results.length > 0) {
                return results;
            }
            if(_count > −1) {
                var expression:RegExp = /w+W*/ig;
                var matches:Array = String(value).match(expression);
                if(matches.length < _count) {
                    results.push(new ValidationResult(true, null, "tooFewWords",
"You must enter at least " + _count + " words."));
                }
            }
            return results;
        }

    }
}

The MXML in Example 15-10 illustrates how you might use WordCountValidator. In this case the count property is set to 5, indicating that the comments text area must contain at least 5 words.

Example 15-10. Using the WordCountValidator custom validator

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:validators="com.oreilly.programmingflex.validators.*" layout="absolute">

    <mx:Form>
        <mx:FormHeading label="Sample Form"/>
        <mx:FormItem label="Comments">
            <mx:TextArea id="comments" />
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="button" label="Submit"/>
        </mx:FormItem>
    </mx:Form>

    <validators:WordCountValidator source="{comments}" property="text" count="5" />

</mx:Application>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset