blob: c0998a6a07f4c7c22c0f3bb37347a7e197f046eb [file] [log] [blame]
------
Input Validation
------
Jesse Kuhnert
------
22 July 2006
------
Input Validation
The tapestry validation system provides a very powerful means of validating data
intuitively on most of the form element components, such as {{{../components/form/textfield.html}TextField}},
{{{../components/form/textarea.html}TextArea}}, {{{../components/form/checkbox.html}Checkbox}}, and so forth. All of these
components implement the interface {{{../apidocs/org/apache/tapestry/form/IFormComponent.html}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 gone). 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 ({{{../components/form/textfield.html}TextField}}, etc.) will
be paired with a {{{../components/form/fieldlabel.html}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"/></td>
</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"/></td>
</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 of {{{../apidocs/org/apache/tapestry/valid/IValidationDelegate.html}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"/> <font color="red">**</font></td>
</tr>
+----------------------------------------------
By subclassing the default implementation of {{{../apidocs/org/apache/tapestry/valid/IValidationDelegate.html}IValidationDelegate}}
(the {{{../apidocs/org/apache/tapestry/valid/ValidationDelegate.html}ValidationDelegate}}
class), you can change how these decorations are rendered. It then becomes a matter of providing this custom
validation delegate to the {{{../components/form/form.html}Form}} component, via its delegate parameter. This is
covered in more detail shortly.
* Field validation
Validation for form element components, such as {{{../components/form/textfield.html}TextField}}
, is controlled by three common component parameters provided by all such
components: <<<validators>>> / <<<translators>>> / and <<<displayName>>>.
The validators parameter provides a list of validator objects, objects that implement the
{{{../apidocs/org/apache/tapestry/form/validator/Validator.html}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 <<<translator>>> parameter configures how the resulting input value should be translated from
its generic String input form to the targeted type, like a <<<Date>>> or double. All translators implement
the {{{../apidocs/org/apache/tapestry/form/translator/Translator.html}Translator}}
interface.
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 {{{../components/form/fieldlabel.html}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
{{{../apidocs/org/apache/tapestry/form/validator/Validator.html}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, {{{../apidocs/org/apache/tapestry/form/validator/MinDate.html}MinDate}}
(which is named "minDate" has a <<<minDate>>> property. A few validators are not configurable
("required" => {{{../apidocs/org/apache/tapestry/form/validator/Required.html}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.
*-----------------+-------------------------------------------+
| {{{../apidocs/org/apache/tapestry/form/validator/Validator.html}Validator}} | attributes |
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/BaseValidator.html}BaseValidator}} | <<<message>>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/Email.html}Email}} | <<<none, uses standard email regexp "^\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,6}$">>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/Max.html}Max}} | <<<max=<maximum value, 10>>>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/MaxDate.html}MaxDate}} | <<<maxDate=<maximum date, 06/09/2010> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/MaxLength.html}MaxLength}} | <<< maxLength=<maximum length, 23> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/Min.html}Min}} | <<< min=<minimum value, 0.718> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/MinDate.html}MinDate}} | <<< minDate=<minimum date, 04/23/05> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/MinLength.html}MinLength}} | <<< minLength=<minmum length, 15> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/Identity.html}Match}} | <<< match=<component to compare against> (since v4.1.2)>>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/validator/Identity.html}Differ}} | <<< differ=<component to compare against> (since v4.1.2)>>>
*-----------------+-------------------------------------------+
** translator: binding prefix
Much like the <<<validators:>>> binding, the
{{{../apidocs/org/apache/tapestry/form/translator/Translator.html}translator}}
binding can be configured with a simple comma-seperated string list to provide rules on how your
incoming data should be translated. Some of these bindings are also used on the client side validation
API to ensure the input format matches your translator parameters.
For example, to validate and translate a TextField bound to a date object you might do something like:
+----------------------------------------------------------
<component id="inputDate" type="TextField">
<binding name="value" value="person.dateValue"/>
<binding name="translator" value="translator:date,pattern=MM-dd-yyyy"/>
<binding name="validators" value="validators:required"/>
<binding name="displayName" value="literal:Date Field"/>
</component>
+----------------------------------------------------------
Currently available translator bindings:
*-----------------+-------------------------------------------+
| {{{../apidocs/org/apache/tapestry/form/translator/Translator.html}Translator}} | attributes |
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/AbstractTranslator.html}AbstractTranslator}} | <<< trim=<true/false> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/StringTranslator.html}StringTranslator}} | <<< trim=<true/false>,empty=<default value if input is empty> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/FormatTranslator.html}FormatTranslator}} | <<< trim=<true/false>,pattern=<any pattern supported by {{{http://java.sun.com/j2se/1.4.2/docs/api/java/text/Format.html}Format}}> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/DateTranslator.html}DateTranslator}} | <<< trim=<true/false>,pattern=<any pattern supported by {{{http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html}DateFormat}}> >>>
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/NumberTranslator.html}NumberTranslator}} | <<< trim=<true/false>,pattern=<any pattern supported by {{{http://java.sun.com/j2se/1.4.2/docs/api/java/text/NumberFormat.html}NumberFormat}}>,omitZero=<true/false> >>> If true (default is false), then values that are 0 are rendered to an empty string, not "0" or "0.00". This is useful in most cases where the field is optional; it allows the field to render blank when no value is present.
*-----------------+-------------------------------------------+
{{{../apidocs/org/apache/tapestry/form/translator/BigDecimalTranslator.html}BigDecimalTranslator}} | <<< trim=<true/false> >>>
*-----------------+-------------------------------------------+
* 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");
}
}
}
+---------------------------------------------------------------