This application uses a custom Validator subclass which performs both client-side and server-side input validation. The client-side validation is done first whenever the First Name field loses focus. If it passes the client-side validation the input is sent to a server for further validation. Standard Flex Validator functionality is used. Right-click the app to view source or download an FXP file here.
Flex provides nice form field validation functionality through its various Validator classes, including:
- CreditCardValidator
- CurrencyValidator
- DateValidator
- EmailValidator
- NumberValidator
- PhoneNumberValidator
- SocialSecurityValidator
- StringValidator
- StyleValidator
- ZipCodeValidator
If one of these doesn’t serve your needs you might make use of the RegExpValidator to customize your validation. And, if that still doesn’t do it you can subclass Validator to write your own validation algorithm. However, sometimes even that’s not enough. Sometimes, you really have to have server-side validation. Maybe you have complex server-side business logic that you don’t want to replicate in the client. Maybe you need to look up something in a database. You could fetch information from the DB and process the validation in Flex but it’s much more efficient and secure to do that kind of thing on the server. In addition, by moving code out of the client and onto the server you may be able to reduce the SWF file size.
But Flex doesn’t provide any built-in support for server-side validation. So, how can you accomplish it? This post shows one technique.
Client-Side and Server-Side Validation
The original inspiration for this technique came from the article Data Services with Server-Side Validation on the i am josh blog. This example differs first, in that it is complete, containing all code needed on both the client side and the server side. Second, this example focuses on validating a single field at a time. Josh’s example includes a ValidateableErrors class which contains error information for all the fields in a form. This implies that the server-side validation is to be done for all fields at once after submitting the form. By contrast, this solution provides maximum responsiveness by first doing whatever simple validation is possible on the client. If an input field is validated in the client-side logic the input is then sent on to the server for additional validation. Each field is validated as soon as it loses focus.
Form Which Uses the Custom Validator
We’ll start with a very simple form which contains just two fields:
<s:VGroup paddingTop="10"> <s:Label text="First Name:"/> <s:TextInput id="firstName" focusOut="firstName_focusOutHandler(event)" /> <s:Label text="Last Name:" /> <s:TextInput /> </s:VGroup>
The first field is the only one which is active in this example. The second field exists only to allow the focus to leave the first one so that validation can be done.
We also have a custom validator object of class ServerValidator:
<local:ServerValidator id="firstNameValidator" property="text" source="{firstName}" />
Linking the validator to the TextInput field as above means that the validator will be called whenever the field loses focus.
We also have an HTTPService to facilitate sending the contents of the firstName text field to the server for validation:
<s:HTTPService id="serverValidator" method="POST" url="http://flexperiential.com/code/ServerSideValidation/validator.php" result="serverValidator_resultHandler(event)" fault="serverValidator_faultHandler(event)" />
Whenever the focus leaves the firstName TextInput field the handler is called to check whether the client-side validation was successful. (If you run the code, the trace statements will show that the validator is called before the focus-out listener.) If the client-side validation was successful, the contents of the firstName field are sent to the server for further checking. The result handler relays the results of the server-side validation to our custom validator class.
protected function serverValidator_resultHandler(event:ResultEvent):void { trace("Validation result: " + event.result.html); firstNameValidator.value = event.result.html; } protected function firstName_focusOutHandler(event:FocusEvent):void { trace("firstName_focusOutHandler"); if(firstNameValidator.localValidationWasSuccessful) { trace("Sending data for server-side validation"); var data:Object ={"firstName" : firstName.text}; serverValidator.send(data); } }
Custom Validator Class
The custom class, ServerValidator, extends Flex’s Validator class:
public class ServerValidator extends Validator { protected var _value:String; private var _localValidationWasSuccessful:Boolean = true; private var _doNeedClientSideValidation:Boolean = true; . .
The three member variables allow the validator class to keep track of the status of the user’s input and its validation. The variable _value contains the user’s current input—but only after it has passed muster with the client-side validation. We saw this being set above in serverValidator_resultHandler.
The variable _localValidationWasSuccessful keeps track of whether the input passed the client-side validation. If not, the form can avoid sending the data to the server. I’ll cover this in more detail below.
Finally, the variable _doNeedClientSideValidation keeps track of which phase the validator is in: client-side validation or server-side validation.
The heart of the validator is the doValidation method which you must override whenever you create a custom Validator:
protected override function doValidation(value:Object):Array { if(_doNeedClientSideValidation) { // Client-side validation trace("Client-side validation"); if(value.toString().toUpperCase().indexOf("D") == -1) // All great names have a "d" (mine does!) { trace("Client-side validation failed"); _doNeedClientSideValidation = true; _localValidationWasSuccessful = false; return [new ValidationResult(true, null, "FAIL_CODE", 'First name must contain a "D"')]; } trace("Client-side validation succeeded"); // Local validation was successful _doNeedClientSideValidation = false; _localValidationWasSuccessful = true; return []; } trace("Server-side validation"); _doNeedClientSideValidation = true; if(_value == "SUCCESS") { trace("Server side validation succeeded"); return []; } else { trace("Server side validation FAILED"); var validationError:ValidationResult = new ValidationResult(true, null, "FAIL_CODE", _value); return [validationError]; } }
If we’re in the client-side validation phase, the first if statement is entered and we check the user’s input which is passed in through the value argument. In this example, I’m looking for the letter “D.” If the input contains the letter “D” the input is valid; otherwise, it’s not. Inside this if statement, we update the two status variables based on whether the input is valid or not. If it was valid we return an empty array which tells Flex that everything is copacetic. And if it was not valid, we return a ValidationResult object containing information about the error.
The rest of the function is concerned with processing the results of the server-side validation. For this example I’ve created a simple PHP file which checks to see if the name contains at least three characters:
<?php $first_name = trim($_POST['firstName']); { if( strlen($first_name) < 3 ) { echo 'Please enter at least three letters'; } else { echo 'SUCCESS'; } } ?>
If it does, the page sends the text “SUCCESS” and, if not, it sends an error message for display to the user. In the MXML form the ServerValidator’s value property is set with the results returned by the server to the HTTPService’s resultHandler. The value setter also calls the Validator class’ validate method which, in turn, causes the doValidation method to be called.
At this point, _doNeedClientSideValidation is false so the first if statement will be skipped. In this example, the value “SUCCESS” is checked for and, if present, the method returns an empty array, again indicating valid input. If anything else is received from the server it’s assumed to be an error message. In this case, a ValidationResult containing the error message is returned.
One Validator per Input Field
Because the validator’s state is closely coupled to the input field’s state it is not possible to use a validator instance with multiple input fields as is sometimes done with standard Flex validators like ZIP code or phone. If this were done, the validator could get out of sync with the state of the input fields and fail to operate correctly.
One last note: in a real form with a submit button (actually, you should never use the word submit; this article on the UX Movement website explains why) you would also want to call all your validators in its click handler.


{ 1 comment… read it below or add one }
David,
Would you mind taking a look at this question: http://stackoverflow.com/questions/5897917/handle-client-and-server-validation-with-flex-3/
I’m having a heck of a time doing this client & server validation, potentially because I have a [Bindable]Model object backing a DataGrid. Any thoughts on this?
Cheers,
Brian
{ 2 trackbacks }