...
Code Block | ||
---|---|---|
| ||
package com.example.newapp.pages; import com.example.newapp.services.UserAuthenticator; import org.apache.tapestry5.annotations.*; import org.apache.tapestry5.corelib.components.Form; import org.apache.tapestry5.corelib.components.PasswordField; import org.apache.tapestry5.ioc.annotations.Inject; public class Login { @Persist @Property@Property private String userName; @Property private String password; @Inject private UserAuthenticator authenticator; @InjectComponent("password") private PasswordField passwordField; @Component private Form loginForm; /** * Do the cross-field validation */ void onValidateFromLoginForm() { if (!authenticator.isValid(userName, password)) { // record an error, and thereby prevent Tapestry from emitting a "success" event loginForm.recordError(passwordField, "Invalid user name or password."); } } /** * Validation passed, so we'll go to the "PostLogin" page */ Object onSuccess() { return PostLogin.class; } } |
...
Code Block | ||
---|---|---|
| ||
<html t:type="layout" title="newapp com.example" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"> <div class="row"> <div class="span4 offset3"> <t:form t:id="loginForm"> <h2>Please sign in</h2> <t:textfield t:id="userName" t:mixins="formgroup" validate="required"/> <t:passwordfield t:id="password" value="password" t:mixins="formgroup" validate="required"/> <t:submit class="btn btn-large btn-primary" value="Sign in"/> </t:form> </div> </div> </html> |
Rendering the page gives a reasonable pleasing first pass:
The Tapestry Form component is responsible for creating the necessary URL for the form submission (this is Tapestry's responsibility, not yours).
...
As a rule of thumb, you should always give your fields a specific id (this id will be used to generate the name
and id
attributes of the rendered tag). Being allowed to omit the value parameter helps to keep the template from getting too cluttered.
The validate
parameter identifies what validations should occur for the field. This is a list of validator names. Validators are configured within Tapestry, and the list of available validators is extensible. "required" is a name of one of the built-in validators, that ensures that the submitted value is not the empty string. Likewise, "minlength ensures that the value has the specified minimum length.
The validate
parameter was placed within the Tapestry namespace using the t:
prefix. This is not strictly necessary, as the template is well formed either way. However, putting the Tapestry specific values into the Tapestry namespace ensures that the template will itself be valid.
Errors and Decorations
Note: This section has not been updated to reflect the introduction of client-side input validation.
When you first activate the Login page, the fields and forms will render normally, awaiting input:
Notice how the Label components are displaying the textual names for the fields. Given that we have not done any explicit configuration, what's happened is that the component's ids ("userName" and "password") have been converted to "User Name" and "Password".
If you just submit the form as is, the fields will violate the "required" constraint and the page will be redisplayed to present those errors to the user:
There's a couple of subtle things going on here. First, Tapestry tracks all the errors for all the fields. The Errors component has displayed them at the top of the form. Further, the default validation decorator has added decorations to the labels and the fields, adding "t-error" to the CSS class for the fields and labels. Tapestry provides a default CSS stylesheet that combines with the "t-error" class to make things turn red.
Next, we'll fill in the user name but not provide enough characters for password.
The user name field is OK, but there's an error on just the password field. The PasswordField component always displays a blank value by default, otherwise we'd see the partial password displayed inside.
If you type in enough characters and submit, we see how the logic inside the Login page can attach errors to fields:
This is nice and seamless; the same look and feel and behavior for both the built-in validators, and for errors generated based on application logic.
...
FormGroup mixin decorates the field with some additional markup, including a <label> element; this leverages more of Bootstrap.
Code Block | ||||
---|---|---|---|---|
| ||||
<div class="form-group">
<label for="userName" class="control-label">User Name</label>
<input id="userName" class="form-control" name="userName" type="text">
</div> |
Form Validation
So, this is a basic (very basic!) form and you can leave the fields blank and submit the form. With very little effort we can add client-side validation.
Validation in Tapestry involves associating one or more validators with a form element component, such as TextField or PasswordField. This can be done using the validate parameter of the component itself.
Available Validators
Tapestry provides the following built-in validators:
...
The annotation may be placed on the getter or setter method, or on the field itself.
Customizing Validation Messages
...