May 5th, 2010 by Lincoln Baxter III

JSF 2.0 Cross-field Form Validation – Simple in Reality

I’d like to start by saying that using JSF by itself can sometimes feel trying to pull your own teeth out with a pair of tweezers, but there’s hope. JSF was designed to be a platform of extensions – a foundation for building web-frameworks, and that it’s done very well. JSF 2.0 addresses most of the concerns about usability (so there’s less tooth pulling,) and provides even more extensibility. That’s where Seam Faces comes in, that’s where PrettyFaces comes in. On many occasions you might find yourself needing to compare the values of multiple input fields on a given page submit: confirming a password; re-enter password; address lookups; and so on. Performing cross-field form validation is simple – just place Seam’s <s:validateForm> component in the form you wish to validate, then attach your custom Validator. I’d like to introduce you to Seam’s intuitive answer, taken directly out of the reference manual. If you want to try it out, you can check out the source or use a snapshot:
        <dependency>
            <groupId>org.jboss.seam.faces</groupId>
            <artifactId>seam-faces</artifactId>
            <version>${seam-faces-version}</version>
        </dependency>

Seam Faces’ <s:validateForm>

<h:form id="locationForm">
     <h:inputText id="city" value="#{bean.city}" />
     <h:inputText id="state" value="#{bean.state}" />
     <h:inputText id="zip" value="#{bean.zip}" />
     <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
 
      <s:validateForm validatorId="locationValidator" />
</h:form>
The corresponding Validator for the example above would look something like this:
@FacesValidator("locationValidator")
public class LocationValidator implements Validator
{
   @Inject
   Directory directory;
 
   @Inject
   @InputField
   private Object city;
 
   @Inject
   @InputField
   private Object state;
 
   @Inject
   @InputField
   private ZipCode zip;
 
   @Override
   public void validate(final FacesContext context, final UIComponent comp, final Object values) throws ValidatorException
   {
      if(!directory.exists(city, state, zip))
      {
         throw new ValidatorException(new FacesMessage("Sorry, that location is not in our database. Please try again."));
      }
   }
}

Tip – You may inject the correct type directly.

@Inject
@InputField
private ZipCode zip;
Notice that the IDs of the inputText components match the IDs of your Validator @InputFields; each @Inject @InputField member will be injected with the value of the form input field who’s ID matches the name of the variable. In other words – the name of the @InputField annotated member variable will automatically be matched to the ID of the input component, unless overridden by using a field ID alias (see below.)
<h:form id="locationForm">
     <h:inputText id="cityId" value="#{bean.city}" />
     <h:inputText id="stateId" value="#{bean.state}" />
     <h:inputText id="zip" value="#{bean.zip}" />
     <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
 
      <s:validateForm fields="city=cityId state=stateId" validatorId="locationValidator" />
</h:form>
The field with ID “zip” will still be referenced normally; you need only specify aliases for fields that differ in name from the Validator @InputFields.

Tip – Using @InputField

Using @InputField("customID") with an ID override can also be used to specify a custom ID, instead of using the default: the name of the field. This gives you the ability to change the name of the private field, without worrying about changing the name of input fields in the View itself.
@Inject
@InputField("state")
private String sectorTwo;

A few last thoughts

First, as of the current version, cross-field validation does not work unless you are using the <s:validateForm> component. As soon as a new version of weld-extensions is released, however, this functionality will work even without the <s:validateForm> component, and you’ll be able to reference cross-fields in any JSF validator! For right now, however, you’ll have to deal with using the component – but – it’s really not that complicated if you think about it 😉 Happy coding!

Posted in Java, OpenSource, Seam

6 Comments

  1. […] @this" render=":messages" />As an extra treat, this form is also using the multiple-component validation feature from Seam, otherwise known as Cross-field validation, or XVal.That’s all for today […]

  2. Hendy Irawan says:

    So this “validate form” functionality is not included with plain JSF 2.0?

    How do we do validation without Seam Faces then?

    1. Lincoln says:

      You’d have to implement a custom validation strategy using JSF’s built-in validation system for validating individual fields.

  3. jitendra says:

    post the code for validation of form with email validation combined like input text blank + email validation

  4. G. T. says:

    I have an similar question to Hendy Irawan.

    I don’t have access to Seam. Is there a way to do cross-field form validation with out resorting to validation during the InvokeApplication phase?

  5. Yanitsa says:

    rfr4ffr

Reply to Lincoln




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.