Creating a custom required RadioButtonGroup Validator class in Flex

Today I was discussing the Validator classes on the Adobe prerelease forum with a couple of other Flex developers. The Flex Validator classes are pretty good for some basic validation and give you a fly-over error message (which you can customize) and a red component outline when the validation fails.

Now, the problem with these validators is that they are geared towards validating one single visual component, such as a TextInput, TextArea, ComboBox, List etc. But what about compound components, such as a DateField combined with a TextInput field for the time? Or, as I will explain in this post, a RadioButtonGroup, which is a non-visual component, but actually comprises the different RadioButton components?

Before I go into how I solved that problem, let me explain a bit about the Flex Validator class. This is the base class for all the different validators and can only check on a field being required or not. This also means that we are going to inherit from this component to create our own validator classes. Of course, you can extend other validator classes as well, but for my purpose of checking to see if a RadioButton in the list has been selected, the Validator base class will be just fine.

<mx:Validator source="{componentToCheck}" property="propertyToCheck" 
              trigger="{componentToMonitor}" triggerEvent="eventToMonitor" 
              required="true(default)|false" 
              requiredError="errorMessage"/>

As you can see in the code sample above there are a couple of important properties in the base class we have to keep in mind when developing our own validator class. First of all, the componentToCheck will be an instance of RadioButtonGroup and the propertyToCheck will be the selection property. You can use the trigger and triggerEvent properties to determine when the validation needs to take place. Leaving out the trigger property and explicitly setting the triggerEvent to an empty string will make sure that the Flex framework will never trigger the validation by itself. That means that we have to do that manually at the exact time that we want the validation to happen.

In the code below you can clearly see the usage of these properties in both <co:RadioGroupValidator/> instances. For all good purposes I’ve also made both a Spark and Halo form to show you the RadioGroupValidator works with both Spark and Halo components.

<fx:Declarations>
	<s:RadioButtonGroup id="rbgSpark"/>
	<mx:RadioButtonGroup id="rbgHalo"/>
	<co:RadioGroupValidator id="vRbgSpark" source="{rbgSpark}" property="selection" triggerEvent=""/>
	<co:RadioGroupValidator id="vRbgHalo" source="{rbgHalo}" property="selection" triggerEvent=""/>
</fx:Declarations>
 
<s:Form defaultButton="{btnSubmitSpark}">
	<s:FormHeading label="Spark form"/>
	<s:RadioButton label="Choice 1" group="{rbgSpark}"/>
	<s:RadioButton label="Choice 2" group="{rbgSpark}"/>
	<s:RadioButton label="Choice 3" group="{rbgSpark}"/>
	<s:RadioButton label="Choice 4" group="{rbgSpark}"/>
	<s:Button id="btnSubmitSpark" label="Submit" click="sparkSubmitHandler(event)"/>
</s:Form>
 
<mx:Form defaultButton="{btnSubmitHalo}">
	<mx:FormHeading label="MX form"/>
	<mx:RadioButton label="Choice 1" group="{rbgHalo}"/>
	<mx:RadioButton label="Choice 2" group="{rbgHalo}"/>
	<mx:RadioButton label="Choice 3" group="{rbgHalo}"/>
	<mx:RadioButton label="Choice 4" group="{rbgHalo}"/>
	<mx:Button id="btnSubmitHalo" label="Submit" click="haloSubmitHandler(event)"/>
</mx:Form>

As for the RadioGroupValidator class itself, the only thing we need to do there is to override the validate method to see wether or not the validation succeeded. If the validation failed we need to loop over all the RadioButton components that belong to this group and set their errorString to the proper message, as you can see in the code below.

import mx.events.ValidationResultEvent;
import mx.validators.Validator;
 
public class RadioGroupValidator extends Validator {
	public function RadioGroupValidator() {
		super();
		requiredFieldError = "Please choose an option from the list."
	}
 
	override public function validate(value:Object=null, suppressEvents:Boolean=false):ValidationResultEvent {
		var result:ValidationResultEvent = super.validate(value, suppressEvents);
 
		for(var i:uint = 0; i < this.source.numRadioButtons; i++) {
			if(result.type == ValidationResultEvent.INVALID) { 
				this.source.getRadioButtonAt(i).errorString = result.message;
			} else {
				this.source.getRadioButtonAt(i).errorString = null;
			}
		}
 
		return result;
	}
}

Now, as you can see I’ve also set the errorString in the constructor to a specific message. This doesn’t mean that you can’t provide your own specific message anymore in the instance declaration. The reason for this is that setting a property in MXML actually uses the implicit setter method and that one is executed after the constructor has initialized the object, which means it will simply overwrite the default value.

This movie requires Flash Player 9

P.S.: If you test the forms, you will see that the Spark form doesn’t show the red error indicator as well as the MX form. Maybe that’s a glitch in the framework, maybe not. I’m still hunting that little sucker down, but no luck so far. I will update this example when I solved this problem.

Share
back

2 comments

  1. Mathias says:

    Nice article about custom validation.

    Though what’s more complicated is the validation of checkboxes because there is no such thing as checkbox-group. I haven’t figured out a implementation of a validator for this yet. I collected all the selections in an array and validate the array according to the validation constraints.

  2. Steven says:

    Hi Mathias,

    Can you explain a bit more on what exactly you are trying to achieve with the checkbox validation? Are you talking about a group of checkboxes and at least one has to be checked? Or is it something else?

Leave a Reply

Your email address will not be published. Required fields are marked *

*