Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
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
languagexml
<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:

Image Added

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:

Image Removed

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:

Image Removed

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.

Image Removed

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:

Image Removed

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
languagexml
titleuserName component as rendered
<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

...