Building Blocks if there’s one thing I know about me and my thoughts: given enough time I’m always wrong

1Feb/0922

Form Validation for the Lazy Programmer in Flex

Forms... Any data-centric application is going to have its fair share of them. They are fairly tedious work. Layout out the form, manage the output, validate the output, over and over. Validation is best when it is active, to let the user know that they have made a mistake before they try to submit the data. Optimally the user won't be allowed to continue until the form data is complete and accurate.

Every form I've written carries the same structure for validation, so as a dedicated lazy programmer I wrote a simple FormValidator class to handle the boilerplate.

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
package com.visualempathy.validators
{
	import flash.display.DisplayObject;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
 
	import mx.events.ValidationResultEvent;
	import mx.validators.Validator;
 
	[Bindable]
	public class FormValidator extends EventDispatcher
	{
		public var formIsValid:Boolean = false;
 
		public var validators:Array;
		private var focusedFormControl:DisplayObject;
 
		public function FormValidator(target:IEventDispatcher=null)
		{
			super(target);
		}
 
		public function validateForm(event:Event):void
		{
			focusedFormControl = event.target as DisplayObject;
			formIsValid = true;
 
			for each( var validator:Validator in validators )
				validate(validator);
		}
 
		private function validate(validator:Validator):Boolean
		{
			var validatorSource:DisplayObject = validator.source as DisplayObject;
			var supressEvents:Boolean = validatorSource != focusedFormControl;
			var event:ValidationResultEvent = validator.validate(null, supressEvents)
			var currentControlIsValid:Boolean = event.type == ValidationResultEvent.VALID;
 
			formIsValid = formIsValid && currentControlIsValid;
			return currentControlIsValid;
		}
	}
}

in the MXML I add an Array structure to hold the Validators, and add the FormValidator like so:

1
2
3
4
5
6
7
8
9
10
	<mx:Array id="validators">
		<mx:StringValidator id="studioNameValidator" source="{this.studioNameInput}" property="text" required="true"/>
		<mx:EmailValidator id="emailValidator" source="{this.emailInput}" property="text" required="true"/>
		<mx:PhoneNumberValidator id="phoneValidator" source="{this.phoneInput}" property="text" required="true"/>
		<mx:StringValidator id="addValidator" source="{this.addressInput}" property="text" required="true"/>
		<mx:StringValidator id="cityValidator" source="{this.cityInput}" property="text" required="true"/>
		<mx:StringValidator id="stateValidator" source="{this.stateInput}" minLength="2" maxLength="2" property="text" required="true"/>
		<mx:ZipCodeValidator id="zipcodeValidator" source="{this.zipcodeInput}" property="text" required="true"/>
	</mx:Array>
	<validators:FormValidator id="formValidator" validators="{this.validators}"/>

This allows you to add an arbitrary number of validators. Then in the various inputs:

1
<mx:TextInput id="studioNameInput" text="{this.studio.name}" width="100%" change="this.formValidator.validateForm(event);"/>

with the button to commit the changes enabled only when the form is valid:

1
<mx:Button id="saveChangesBtn" label="save" click="handleSaveChanges()" enabled="{this.formValidator.formIsValid}"/>

It reduces some of the pain and tedium with the process of creating forms, which is always welcome.

  • kwigg22
    Does this work? I keep getting prefix element is not bound for the validators:FormValidator line
  • Neat stuff!! great work
  • Surendragurjar
    Great work.....
  • You are a gentleman and a scholar.
  • Reggie
    This doesn't work for ComboBox form items.
  • Combo boxes require object validators. It does work, you just
    generally need a custom validator.
  • Does it compatible with various forms..?
  • Does anybody know what happend to the validator in Flash Builder (flex 4) ??? i seem to have all sorts of errors occuring when using it with sparks.
  • I just wanted to say that this came in handy and saved me from having to write the ~100 lines to do it :-)

    Cheers!
  • Alfonso
    Hi, I'm creating a tab navigator and my form is on the second tab, when I call validate, I'm getting an error because
    var validatorSource:DisplayObject = validator.source as DisplayObject
    returns null.

    How can I fix it?

    thanks
  • travis
    never mind i figured it out just got rid of the array and called the FormValidator class for each text input which makes each form unique
  • travis
    question? I"m creating an update form. Every text input has an update button. How can I make it so I toggle each button to be enabled or disabled on verification. Thanks
  • travis
    Thanks for this its way cleaner then a lot of other examples out there
  • Steve
    Hey, nice solution Joel, more elegant than mine, which was puely actionscript and flag setting/checking.

    I too seem to always be building forms and WIZARDS... your soultion works brilliantly as a mechanism of validating before the next wizard pane is shown/ next button to move to the next pane is enabled.
  • Joel
    Assuming you are referring to the AdvancedForm, then yes. AdvancedForm is a container and carries the baggage of extending Form. It is a great component, but many times I want to lay out a form, not a Form, and have freedom in how I use my visual space.

    Then again, maybe you are referring to something entirely different, in that case you'd need to be more specific.
  • Doesn't FlexLib already have such a device ?
blog comments powered by Disqus