From @ocpsoft and @lincolnthree. Read the original article on OcpSoft.
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.author}" />
<h:inputText id="state" value="#{bean.title}" />
<h:inputText id="zip" value="#{bean.text}" />
<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.author}" />
<h:inputText id="stateId" value="#{bean.title}" />
<h:inputText id="zip" value="#{bean.text}" />
<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!
About the author:
Lincoln Baxter, III is a Senior Software Engineer at Red Hat, Inc., working on JBoss open-source projects. This blog represents his personal thoughts and perspectives, not necessarily those of his employer.
He is a founder of OcpSoft, the author of PrettyFaces: bookmarking, SEO extensions for JSF, and an individual member of the JavaServer™ Faces Expert Group. When he is not swimming, running, or playing Ultimate Frisbee, Lincoln is focused on promoting open-source software and making web-applications more accessible for small businesses, individuals. His latest project is ScrumShark, an open-source, agile project management tool.