Jakarta > Tapestry
Jakarta
 

Input Validation

The tapestry validation system provides a very powerful means of validating data intuitively on most of the form element components, such as TextField, TextArea, Checkbox, and so forth. All of these components implement the interface IFormComponent, and include the necessary hooks to fit into the overall validation framework.

Localization, server-side, and client side validation are handled by the framework, as well as the ability to extend or override most of the built in functionality to suit your purposes as you see fit.

Validation has evolved over time (the first attempt at proper validation using Tapestry occured back in 2001). Through Tapestry 3, validation was limited to the ValidField component (which is now deprecated). For Tapestry 4, the APIs related to validation were effectively rewritten, resulting in a more powerful, more extensible approach that can be used with all kinds of form element components.

FieldLabel component

Generally speaking, every form input component (TextField, etc.) will be paired with a FieldLabel component. The FieldLabel is responsible for generating the HTML <label> element, which is extremely effective for accessible user interfaces (user interfaces that work for people with visual disabilities). Typical usage:

<tr>
   <td><label jwcid="@FieldLabel" field="component:userName">User Name</label></td>
   <td><input jwcid="userName@TextField" value="ognl:userName" validators="validators:required" displayName="User Name" size="30"/>
</tr>

At runtime, this may render as:

<tr>
   <td><label for="userName">User Name</label></td>
   <td><input name="userName" id="userName" value="" size="30"/>
</tr>

However, this is not all there is to FieldLabel. An important part of validation is decoration of fields, to mark when they contain errors. This is one of the responsibilities IValidationDelegate ... decorating fields and labels.

If the above form is submitted without specifying a user name, the userName field will be in error. The page will be redisplayed to show the user the error message and the decorated fields and labels. The default decoration is primitive, but effective:

<tr>
   <td><font color="red"><label for="userName">User Name</label></font></td>
   <td><input name="userName" id="userName" value="" size="30"/>&nbsp;<font color="red">**</font>
</tr>

By subclassing the default implementation of IValidationDelegate (the ValidationDelegate class), you can change how these decorations are rendered. It then becomes a matter of providing this custom validation delegate to the Form component, via its delegate parameter. This is covered in more detail shortly.

Field validation

Validation for form element components, such as TextField, is controlled by two common component parameters provided by all such components: validators and displayName.

The validators parameter provides a list of validator objects, objects that implement the Validator interface. Why a list? Unlike Tapestry 3 validation, each individual validator checks just a single constraint. Contraints are things like minimum string length, maximum string length, minimum numeric value, etc. This is a very fine grained approach, and one that is easily extensible to new contraints.

The displayName parameter is used to provide the label for the component (perhaps some day, this parameter will be renamed to "label"; why it has such a cumbersome name has been forgotten). In any case, this label is used by the matching FieldLabel component, and is also incorporated into an error messages created for the component.

validators: binding prefix

The validators: binding prefix is a powerful shorthand for constructing a list of configured Validator objects. It allows a very declarative style; for example, to state that a field is required with a minimum length of four characters, the following parameter binding could be used (in a page or component specification):

<binding name="validators" value="validators:required,minLength=4"/>    
    

Notice that the actual type of the data isn't specified in this instance, it is implied by which parameters you specify. A specification is a comma-seperated list of entries. Each entry is in one of the following forms:

  • name
  • name=value
  • name[message]
  • name=value[message]
  • $name

Most validator classes are configurable: they have a property that matches their name. For example, MinDate (which is named "minDate" has a minDate property. A few validators are not configurable ("required" => Required, for example).

Validators are expected to have a public no-args constructor. They are also expected to have a message property which is set from the value in brackets. The message is either a literal string, or may be prefixed with a '%' character, to indicate a localized key, resolved using the component's message catalog.

When the name is prefixed with a dollary sign, it indicates a reference to a <bean> with the given name.

A full validator specification might be: required,email[%email-format],minLength=20[Email addresses must be at least 20 characters long.]

Here is a partial list of the validator classes provided and their configurable attributes.

Fixme (Jesse Kuhnert)
Fill in all of the possible attributes started in the table below.
Validator attributes
BaseValidator message
Email none, uses standard email regexp "^\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,6}$"
Max max=<maximum value, 10>
MaxDate maxDate=<maximum date, 06/09/2010>
MaxLength maxLength=<maximum length, 23>
Min min=<minimum value, 0.718>
MinDate minDate=<minimum date, 04/23/05>
MinLength minLength=<minmum length, 15>
Fixme (Jesse Kuhnert)
Examples!
Fixme (Jesse Kuhnert)
Write about how the validation constraints specified with the above syntax are universally applied on both the client and server-side, as well as how to override the default behaviour for displaying client-side validation messages via subclassing the Tapestry.default_invalid_field_handler javascript prototyped method.

Extending ValidationDelegate

There are a lot of scenerios where you may wish to do something more than that provided by the default, like apply a CSS class to labels in error, or even provide the ability to render the error message directly in or around the label or field.

Below is a typical subclass of ValidationDelegate that provides more application-specific decorations:

/**
 * Provides more intelligent validation delegate support.
 */
public class MyValidationDelegate extends ValidationDelegate {

/**
 * This method is overwritten so that the error message generated during 
 * server-side validation actually appears next to the field in question.
 *
 * Don't be confused by the method names, there is a complimenting writeSuffix
 * for fields, as well as a pair of writeLabelSuffix/writeLabelPrefix methods to
 * do the same to labels.
 * {@inheritDoc}
 */
 public void writePrefix(IMarkupWriter writer, IRequestCycle cycle, 
         IFormComponent component, IValidator validator)
 {
     IFieldTracking ft = getCurrentFieldTracking();
     //there is a default error renderer for fields which simply
     //writes the message, which is what we want to have happen in this case
     if (ft != null && ft.getErrorRenderer() != null) 
         ft.getErrorRenderer().render(writer, cycle);
 }
 
 /**
  * Adds a class style attribute to the label if in error
  * {@inheritDoc}
  */
 public void writeLabelAttributes(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component) {
      if (isInError(component))
      {
         writer.attribute("class", "labelError");
      }
 }
 
 }

ValidField component

Warning
The ValidField component and it's associated validators under org.apache.tapestry.valid should be considered deprecated in favor of the new system found under org.apache.tapestry.form.validator.

validator: binding prefix

For ValidField, validation is specified through a single parameter, validator. The validator parameter is an object that implements the IValidator interface. In Tapestry 3.0, it was necessary to provide a configured Java object as the validator, using Java code, or the specification's <bean> element.

Although the ValidField component is deprecated in release 4.0 (and likely to be removed in a later release), some legacy support for ValidField was added in release 4.0 ... a special binding prefix, "validator:", that streamlines the process of assembling a validator object for the validator parameter.

The validator: binding prefix is a powerful shorthand for specifying validators. The string provided does two things: it identifies (by a short logical name) the Java class of the validator to create, and it specifies (as a comma seperated list) the properties of the validator to set. The form of the string is:

        validator:name[,property[=value]]*
      

The name corresponds to contributions to the tapestry.valid.Validators configuration point. After the name is a list of properties to set. A simple conversion from string value to actual data type is performed. For boolean properties, the value can be skipped and will default to true. Alternatively, the value can be prefixed with an exclamation point, and the property will be set to false. Example:

        validator:string,required,minimumLength=5
      

In some cases, this is insufficiently powerful to set the properties of the validator instance, in which case the <bean> element can be used instead.

The following validator names are defined:

Name IValidator implementation class
string StringValidator
date DateValidator
email EmailValidator
url UrlValidator
int IntValidator