13
Aug
07

Validating Flex forms using the Validator classes

Another quick post on validating a form using the StringValidator, NumberValidator, ZipCodeValidator and Validator classes. Not sure if this is the best method, but I used the NumberValidator to validate that a ComboBox has a valid selection (the selectedIndex property was equal to or greater than 0), and I used a combination of StringValidator and ZipCodeValidator to make sure that the user enters a US Zip+4 zip code.

Got some good Flex Validator tips? Leave em in the comments!

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/13/validating-flex-forms-using-the-validator-classes/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical"
    verticalAlign="middle"
    backgroundColor="white"
    creationComplete="init()">

    <mx:Script>
        <![CDATA[
            import mx.validators.Validator;
            import mx.events.ValidationResultEvent;
            import mx.validators.ZipCodeValidatorDomainType;
            import mx.controls.Alert;

            [Bindable]
            private var validatorArr:Array;

            private function init():void {
                validatorArr = new Array();
                validatorArr.push(shippingName_stringValidator);
                validatorArr.push(shippingAddress1_stringValidator);
                validatorArr.push(shippingCity_stringValidator);
                validatorArr.push(shippingState_numberValidator);
                validatorArr.push(shippingZipCode_zipCodeValidator);
                validatorArr.push(shippingZipCode_stringValidator);
            }

            private function validateForm(evt:MouseEvent):void {
                var validatorErrorArray:Array = Validator.validateAll(validatorArr);;
                var isValidForm:Boolean = validatorErrorArray.length == 0;
                if (isValidForm) {
                    Alert.show("The form is valid!", "Valid form...");
                } else {
                    var err:ValidationResultEvent;
                    var errorMessageArray:Array = [];
                    for each (err in validatorErrorArray) {
                        var errField:String = FormItem(err.currentTarget.source.parent).label
                        errorMessageArray.push(errField + ": " + err.message);
                    }
                    Alert.show(errorMessageArray.join("\n\n"), "Invalid form...", Alert.OK);
                }
            }

            private function resetForm(evt:MouseEvent):void {
                shippingName.text = "";
                shippingAddress1.text = "";
                shippingAddress2.text = "";
                shippingCity.text = "";
                shippingState.selectedIndex = -1;
                shippingZipCode.text = "";
            }
        ]]>
    </mx:Script>

    <mx:XMLList id="statesXMLList">
        <state label="California" data="CA" />
        <state label="Oregon" data="OR" />
    </mx:XMLList>

    <mx:StringValidator id="shippingName_stringValidator"
        source="{shippingName}"
        property="text"
        minLength="2" />

    <mx:StringValidator id="shippingAddress1_stringValidator"
        source="{shippingAddress1}"
        property="text"
        minLength="2" />

    <mx:StringValidator id="shippingCity_stringValidator"
        source="{shippingCity}"
        property="text"
        minLength="2" />

    <mx:NumberValidator id="shippingState_numberValidator"
        source="{shippingState}"
        lowerThanMinError="This field is required."
        property="selectedIndex"
        minValue="0" />

    <mx:ZipCodeValidator id="shippingZipCode_zipCodeValidator"
        source="{shippingZipCode}"
        property="text"
        requiredFieldError="Please enter a zip code in ZIP+4 format."
        domain="{ZipCodeValidatorDomainType.US_ONLY}"  />

    <mx:StringValidator id="shippingZipCode_stringValidator"
        source="{shippingZipCode}"
        property="text"
         tooShortError="Please enter a zip code in ZIP+4 format."
        minLength="10" maxLength="10" />

    <mx:Form>
        <mx:FormHeading label="Shipping Information" />
        <mx:FormItem required="true" label="Name">
            <mx:TextInput id="shippingName" maxChars="96" />
        </mx:FormItem>
        <mx:FormItem required="true" label="Address">
            <mx:TextInput id="shippingAddress1" maxChars="128" />
        </mx:FormItem>
        <mx:FormItem label="">
            <mx:TextInput id="shippingAddress2" maxChars="128" />
        </mx:FormItem>
        <mx:FormItem required="true" label="City">
            <mx:TextInput id="shippingCity" maxChars="128" />
        </mx:FormItem>
        <mx:FormItem required="true" label="State">
            <mx:ComboBox id="shippingState" prompt="Please select a State..." selectedIndex="-1" dataProvider="{statesXMLList}" labelField="@label" />
        </mx:FormItem>
        <mx:FormItem required="true" label="ZIP Code">
            <mx:TextInput id="shippingZipCode" maxChars="10" restrict="0-9 -" />
        </mx:FormItem>
        <mx:FormItem>
            <mx:HBox>
                <mx:Button label="Submit" click="validateForm(event)" />
                <mx:Button label="Reset" click="resetForm(event)" />
            </mx:HBox>
        </mx:FormItem>
    </mx:Form>

</mx:Application>

View source is enabled in the following example.


21 Responses to “Validating Flex forms using the Validator classes”


  1. 1 Bruce Aug 14th, 2007 at 6:16 am

    Very nice validation example. You may want to change this line:

    Alert.show(errorMessageArray.join("nn"), "Invalid form...", Alert.OK);
    

    to

    Alert.show(errorMessageArray.join("\n"), "Invalid form...", Alert.OK);
    

    Using “\n” will cause each error to display on its own line.

  2. 2 peterd Aug 14th, 2007 at 6:50 am

    Thanks Bruce,

    Apparently I needed to put two backslashes for it to show up in the entry above. *shrug*

  3. 3 Tony Sep 1st, 2007 at 2:13 pm

    Nice Example. Perfect for what I needed.
    If someone has a better way, I would love to know what it is.

  4. 4 Tony Sep 4th, 2007 at 9:15 am

    Peter,

    I have a suggestion for this one that may help out in the case you are using a credit card validator. The parent is stored in a different place. You can also check out my formatting.

    for each (err in validatorErrorArray) {
    	var formItem:FormItem;
    	///trace("ClassName",getQualifiedClassName(err.currentTarget).split("::")[1]);
    	switch (getQualifiedClassName(err.currentTarget).split("::")[1]){
    		case "CreditCardValidator":
    			formItem = err.currentTarget.cardNumberSource.parent;
    		break;
    		case "StringValidator":
    			formItem = err.currentTarget.source.parent;
    		break;
    		case "ZipCodeValidator":
    			formItem = err.currentTarget.source.parent;
    		break;
    		default:
    			formItem = new FormItem();
    			formItem.label = "Misc.";
    		break;
    	}
        errorMessageArray.push(formItem.label   ": \n\t"   err.message.replace(new RegExp('\n','g'),"\n\t"));
    }
    

    Regards,
    Tony

  5. 5 Nice Sep 10th, 2007 at 9:35 pm

    AWESOME….

    Is there a way to display the textInput Name Error message?

    I changed the code, but doesn’t work for me.

    from:

    var errField:String = FormItem(err.currentTarget.source.parent).label
    

    to:

    var errField:String = TextInput(err.currentTarget.source.parent).id
    

    CHEERS & THANKS

  6. 6 peterd Sep 11th, 2007 at 12:37 am

    Nice,

    Not sure if you’re using the example from above or a modified version (I’ll assume its the code from above), but I can get the control’s “id” by using the following snippet from the validateForm() method:

    for each (err in validatorErrorArray) {
        var errField:String = err.currentTarget.source.id;
        errorMessageArray.push(errField   ": "   err.message);
    }
    

    You should take out the “parent” from the path since I was jumping up to the FormItem control to grab the label property.

    Hope that helps,

    Peter

  7. 7 valentineday Sep 12th, 2007 at 12:38 pm

    Peterd, you are so cool.. Now I can get the id :)

    I was wondering how to verify check box in the form, most form contents check box! -_- Base on the example above, how to add a check box and return all errors in Alert.show box? any suggestion?

    have a nice day

  8. 8 peterd Sep 12th, 2007 at 1:10 pm

    valentineday,

    Not strictly related to the previous example, but here is one way to use a validator to see if a check box is selected. Note that I’m validating against a <mx:Model /> here, and I’m converting the data type from a Boolean to a Number. I’m sure there are other/better ways, but I threw this together somewhat quickly.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white">
    
        <mx:Script>
            <![CDATA[
                import mx.events.ValidationResultEvent;
                import mx.controls.Alert;
    
                private function validateCheckBox():void {
                    num.val = Number(agree.selected);
                    var result:ValidationResultEvent = numVal.validate();
    
                    switch (result.type) {
                        case ValidationResultEvent.INVALID:
                            agree.errorString = result.message;
                            break;
                        case ValidationResultEvent.VALID:
                            Alert.show("If you can see this, you must have selected the check box.", "Valid!!!!");
                            agree.errorString = null;
                            break;
                    }
                }
            ]]>
        </mx:Script>
    
        <mx:Model id="num">
            <val />
        </mx:Model>
    
        <mx:Array>
            <mx:NumberValidator id="numVal"
                    source="{num}"
                    property="val"
                    minValue="1"
                    lowerThanMinError="Please agree before continuing." />
        </mx:Array>
    
        <mx:CheckBox id="agree"
                label="I have pretended to read your EULA."
                selected="false" />
    
        <mx:Button label="Continue"
                click="validateCheckBox();" />
    
    </mx:Application>
    

    Hope that helps,

    Peter

  9. 9 levan Sep 28th, 2007 at 10:01 am

    I think thats to extra its easier to just write BooleanValidator here I did it quick and dirty way stripped down code from StringValidator.:

    public class BooleanValidator extends Validator
    {
    
        /**
         *  @private
         *  Loads resources for this class.
         */
        private static function loadResources():void
        {
    
        }
    
        public static function validateBoolean(validator:BooleanValidator,
                                              value:Boolean,
                                              baseField:String = null):Array
        {
            var results:Array = [];
            if (!value)
            {
                results.push(new ValidationResult(true));
                return results;
            }
    
            return results;
        }
    
        /**
         *  Constructor.
         */
        public function BooleanValidator()
        {
            super();
    
        }
    
        override protected function doValidation(value:Object):Array
        {
            var results:Array = super.doValidation(value);
    
            // Return if there are errors
            // or if the required property is set to false and length is 0.
            var val:String = value ? String(value) : "";
            if (results.length > 0 || ((val.length == 0) && !required))
                return results;
            else
                return BooleanValidator.validateBoolean(this, (value as Boolean), null);
        }
    }
    

    I think you are doing way too much extra just to get checkbox validate.

  10. 10 levan Sep 28th, 2007 at 10:03 am

    after that you can just do :

    var temp2:BooleanValidator = new BooleanValidator();
    aComp.addEventListener(Event.CHANGE,checkFields);
    temp2.source=aComp;/// refference to your checkbox
    temp2.property="selected";
    temp2.required=true;
    myValidators.addItem(temp);
    
  11. 11 peterd Sep 28th, 2007 at 6:44 pm

    levan,

    Great tip, thanks!

    Peter

  12. 12 Gareth Oct 19th, 2007 at 7:24 pm

    Does anyone know how to use the source and property fields to do a credit card validation in actionscript? I know that I can use the cardTypeSource and property and the cardNumberSource and property to do it, but I’m trying to make it more generic, and, according to the livedocs, it is possible by passing an object. However, I’ve tried just about every variation I can think of, but none of them work.

    This is the part that’s confusing me

    Use the source and property properties to specify a single Object. The Object should contain the following fields:

    cardType - Specifies the type of credit card being validated.
    In MXML, use the values: “American Express”, “Diners Club”, “Discover”, “MasterCard”, or “Visa”.
    In ActionScript, use the static constants CreditCardValidatorCardType.MASTER_CARD, CreditCardValidatorCardType.VISA, or CreditCardValidatorCardType.AMERICAN_EXPRESS CreditCardValidatorCardType.DISCOVER, or CreditCardValidatorCardType.DINERS_CLUB.

    cardNumber - Specifies the number of the card being validated.

    I’ve done ccObj:object = { cardNumber: myCardNumField, cardType: myCardTypeField }
    for the source, but then I don’t know what string to use for the property (as property appears that it has to be a string).

    Anyone have any ideas?

  13. 13 peterd Oct 19th, 2007 at 11:30 pm

    Gareth,

    I just whipped this up (“Creating a credit card validator in ActionScript”), although now re-reading your question I’m not sure if I answered the right thing.

    Was that roughly what you were looking for? Or were you looking for something more specific to the object syntax?

    Peter

  14. 14 Gareth Nov 1st, 2007 at 1:34 pm

    Hey Peter,
    finally got around to this post again. Thanks for the post. That definitely makes it easier to understand. I guess what confused me previously was that the object would be the source and the properties for each would be the the actual properties of the object. I’m not sure what it was I was trying, but whatever I was doing was not working. This will definitely help.
    Thanks.

  15. 15 Halfway there... Mar 21st, 2008 at 2:10 pm

    Sorry, but this is not a good example. Way too much boilerplate code and no reusability. It’s also missing some of the instant error feedback (indicate after each keystroke whether your form input is valid or invalid - come on, javascript forms can do this…) or even basic expected functionality such as having the enter key “revalidate” the input component or something.

    What if you have 10 forms with 5-20 fields each? Are we supposed to copy and paste all that stuff for every field, every form? It’s not easily pulled out into a custom component.

    Nice for simple cases but serious apps will demand more than this…

  16. 16 دردشة Apr 26th, 2008 at 8:11 am

    the type of credit card being validated

  17. 17 flexlingie Jun 19th, 2008 at 3:01 pm

    Great blog posting. I like the idea of a BooleanValidator!
    Thanks!

  18. 18 Tanya R Jun 25th, 2008 at 1:29 pm

    Great Examples.

    i have a quesiton about combobox, it seems that when the page first loads, my comboboxes are marked as invalid right away, even before the submit button is clicked.

    In your sample however, they do not have the red border around them initially…. is there a way to fix it?

    this is a snippit of my code:

    [code]

    [/code]

    and

    [code]

    [/code]

    please help me, i can’t seem to find a solution to this anywere.

    Thanks!
    -Tanya

  19. 19 Tanya R Jun 25th, 2008 at 1:29 pm

    oh oh, the code didn’t show… but i hope you get the main idea of my issue.

    Thanks!

  20. 20 Nate R Jul 1st, 2008 at 1:44 pm

    Tanya,

    Here is what I did to get the ComboBox’s border to show as red when invalid.

    <mx:NumberValidator id="validator" source="{combo}" property="selectedIndex" minValue="0" invalid="changeComboBorder(event)" valid="changeComboBorder(event)" />
    
    private function changeComboBorder(event:ValidationResultEvent):void {
      var validator:Validator = event.target as Validator;
      var comboBox:ComboBox = validator.source as ComboBox;
    
      if (event.type == ValidationResultEvent.VALID) {
        comboBox.setStyle("borderColor", 0xB7BABC);
      }
      else {
        comboBox.setStyle("borderColor", 0xFF0000);
      }
    }
    

    Hopefully this helps.

  21. 21 Aasim Aug 8th, 2008 at 2:23 am

    I guess what Tanya wanted to point was that the ComboBox control is validated on creation. The solution to her query can be achieved by setting the triggerEvent on the validator to “focusOut” of the source.

    This would trigger the validation of the comboBox on moving focus from the comboBox.

    code below–

    <mx:NumberValidator id="comboValidator" required="true" minValue="0"
        	invalid="changeComboBorder(event)" valid="changeComboBorder(event)"
        	triggerEvent="focusOut"
        	source="{trialCombo}" property="selectedIndex" />
    

Leave a Reply

This blog is terrible at eating HTML tags. If you plan on posting code/XML, please escape your "<" characters as "&lt;" and your ">" characters as "&gt;".




Badge Farm

  • Firefox 2
  • Powered by Redoable 1.2
  • Feeds burnt by Feedburner
  • Feed