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> |
<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> |
<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."));
}
}
} |
@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; |
@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> |
<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; |
@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!
[…] @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 […]
So this “validate form” functionality is not included with plain JSF 2.0?
How do we do validation without Seam Faces then?
You’d have to implement a custom validation strategy using JSF’s built-in validation system for validating individual fields.
post the code for validation of form with email validation combined like input text blank + email validation
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?
rfr4ffr