...
Finally, Tapestry is able to not only present the errors back to the user, but to decorate the fields and the labels for the fields, marking them as containing errors (primarily, using CSS effects).
Contents
The Form Component
The core of Tapestry's form support is the Form component. The Form component encloses (wraps around) all the other field components such as TextField, TextArea, Checkbox, etc.
...
For example, a Login page, which collects a user name and a password, might look like:
Code Block |
---|
|
public class Login
{
@Persist
@Property
private String userName;
@Property
private String password;
@Inject
private UserAuthenticator authenticator;
@InjectComponent(id = "password")
private PasswordField passwordField;
@Component
private Form form;
/**
* Do the cross-field validation
*/
void onValidateFromLoginForm()
{
if (!authenticator.isValid(userName, password))
{
// record an error, and thereby prevent Tapestry from emitting a "success" event
form.recordError(passwordField, "Invalid user name or password.");
}
}
/**
* Validation passed, so we'll go to the "PostLogin" page
*/
Object onSuccess()
{
return PostLogin.class;
}
}
|
...
The template for the Login page contains a minimal amount of Tapestry instrumentation:
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
<head>
<title>Login</title>
</head>
<body>
<h1>Please Login</h1>
<form t:type="form" t:id="loginForm">
<t:errors/>
<t:label for="userName"/>:
<input t:type="TextField" t:id="userName" t:validate="required,minlength=3" size="30"/>
<br/>
<t:label for="password"/>:
<input t:type="PasswordField" t:id="password" t:validate="required,minlength=3" size="30"/>
<br/>
<input type="submit" value="Login"/>
</form>
</body>
</html>
|
...
For example, your template may have the following:
Code Block |
---|
|
<t:textfield t:id="ssn" validate="required,regexp"/>
|
And your message catalog can contain:
Code Block |
---|
|
ssn-regexp=\d{3}-\d{2}-\d{4}
ssn-regexp-message=Social security numbers are in the format 12-34-5678.
|
...
Validation Macros
Lists of validators can be combined into validation macros. This mechanism is convenient for ensuring consistent validation rules across an application. To create a validation macro, just contribute to the ValidatorMacro Service in your module class (normally AppModule.java), by adding a new entry to the configuration object, as shown below. The first parameter is the name of your macro, the second is a comma-separated list of validators:
Code Block |
---|
|
@Contribute(ValidatorMacro.class)
public static void combinePasswordValidators(MappedConfiguration<String, String> configuration) {
configuration.add("password","required,minlength=5,maxlength=15,");
}
|
Then, you can use this new macro in component templates and classes:
Code Block |
---|
|
<input t:type="textField" t:id="password" t:validate="password" />
|
Code Block |
---|
|
@Validate("password")
private String password;
|
...
For example, you may have a quantity field that you wish to display as blank, rather than zero, initially:
Code Block |
---|
|
<t:textfield t:id="quantity" size="10"/>
. . .
private int quantity;
String onToClientFromQuantity()
{
if (quantity == 0) return "";
return null;
}
|
...
That's where the "parseclient" event comes in:
Code Block |
---|
|
Object onParseClientFromQuantity(String input)
{
if ("".equals(input)) return 0;
return null;
}
|
...
Now, what if you want to perform your own custom validation? That's another event: "validate":
Code Block |
---|
|
void onValidateFromCount(Integer value) throws ValidationException
{
if (value.equals(13)) throw new ValidationException("Thirteen is an unlucky number.");
}
|
...