The Validate Event

In the previous example we saw programmatic validation done in the Form's validate event handler. Here we demonstrate a second common approach, which takes advantage of the fact that before Form bubbles up validate, each input component also bubbles up validate!

Instead of putting all the validation in one handler, we provide one handler per field and one for the Form. In this approach, our Form handler validates dependencies between the fields, also known as "cross-form validation".
Enter your First Name OR your Lucky Number:

(size max = 10, letters only)

(min=1, max=100, not 13)

Which approach is best? The choice is yours.

References: AbstractTextField, Form, Errors, Forms and Validation.

Home


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<body class="container">
    <h3>The Validate Event</h3>
    
    In the previous example we saw programmatic validation done in the Form's <em>validate</em> event handler.   
    Here we demonstrate <strong>a second common approach</strong>, which takes advantage of the fact that before Form 
    bubbles up <em>validate</em>, each input component also bubbles up <em>validate</em>!<br/><br/>
    
    Instead of putting all the validation in one handler, we provide one handler per field and one for the Form. 
    In this approach, our Form handler validates dependencies between the fields, also known as 
    <strong>"cross-form validation"</strong>.
    
    <div class="eg">
        <t:form  class="form-horizontal" t:id="inputs">
            <div style="padding-bottom: 8px;">Enter your First Name OR your Lucky Number:</div>
            
            <div class="form-group">
                <t:label for="firstName" class="col-sm-3"/>
                <div class="col-sm-3">
                    <t:textfield t:id="firstName"/>
                </div>
                <div class="col-sm-6">
                    <p class="form-control-static">
                        ${firstName}
                        <span class="text-muted">
                            (size max = 10, letters only)
                        </span>
                    </p>
                </div>
            </div>
            <div class="form-group">
                <t:label for="luckyNumber" class="col-sm-3"/>
                <div class="col-sm-3">
                    <t:textfield t:id="luckyNumber"/>
                </div>
                <div class="col-sm-6">
                    <p class="form-control-static">
                        ${luckyNumber}
                        <span class="text-muted">
                            (min=1, max=100, not 13)
                        </span>
                    </p>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-3 col-sm-offset-3">
                    <t:submit/>
                </div>
            </div>
            
            <t:errors globalOnly="true"/>
        </t:form>
    </div>

    Which approach is best? The choice is yours.<br/><br/>

    References: 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/base/AbstractTextField.html">AbstractTextField</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/Errors.html">Errors</a>, 
    <a href="http://tapestry.apache.org/forms-and-validation.html">Forms and Validation</a>.<br/><br/>
    
    <t:pagelink page="Index">Home</t:pagelink><br/><br/>
        
    <t:tabgroup>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/input/TheValidateEvent.tml"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/input/TheValidateEvent.java"/>
        <t:sourcecodetab src="/web/src/main/resources/META-INF/assets/css/examples/plain.css"/>
    </t:tabgroup>
</body>
</html>


package jumpstart.web.pages.examples.input;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;

import org.apache.tapestry5.PersistenceConstants;
import org.apache.tapestry5.ValidationException;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Form;

@Import(stylesheet = "css/examples/plain.css")
public class TheValidateEvent {

    // Screen fields

    @Property
    @Persist(PersistenceConstants.FLASH)
    @Size(max = 10)
    private String firstName;

    @Property
    @Persist(PersistenceConstants.FLASH)
    @Min(1)
    @Max(100)
    private Integer luckyNumber;

    // Generally useful bits and pieces

    @InjectComponent("inputs")
    private Form form;

    // The code

    void onValidateFromFirstName(String value) throws ValidationException {

        // Error if doesn't contain letters only.

        if (value != null) {
            if (!value.matches("[A-Za-z]+")) {
                throw new ValidationException("First Name must contain letters only");
            }
        }

    }

    void onValidateFromLuckyNumber(Integer value) throws ValidationException {

        // Error if number 13 chosen.

        if (value != null) {
            if (value.equals(13)) {
                throw new ValidationException("Sorry, but 13 is not a lucky number.");
            }
        }

    }

    /**
     * Cross-form validation goes in here.
     */
    void onValidateFromInputs() {

        if (form.getHasErrors()) {
            return;
        }

        // Error if neither chosen.

        if (firstName == null && luckyNumber == null) {
            form.recordError("Please specify first name or lucky number.");
        }

        // Error if both chosen.

        if (firstName != null && luckyNumber != null) {
            form.recordError("Please do not specify both.");
        }
    }

}


.eg {
                margin: 20px 0;
                padding: 14px;
                border: 1px solid #ddd;
                border-radius: 6px;
                -webkit-border-radius: 6px;
                -mox-border-radius: 6px;
}