Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF doesn't support cross-field validation, is there a workaround?

JSF 2.0 only allows you to validate the input on one field, like check to see if it's a certain length. It doesn't allow you to have a form that says, "enter city and state, or enter just a zip code."

How have you gotten around this? I'm only interested in answers that involve the validation phase of JSF. I'm not interested in putting validation logic in Managed Beans.

like image 498
Jonathan S. Fisher Avatar asked Jun 08 '11 17:06

Jonathan S. Fisher


2 Answers

The easiest custom approach I've seen and used as far is to create a <h:inputHidden> field with a <f:validator> wherein you reference all involved components as <f:attribute>. If you declare it before the to-be-validated components, then you can obtain the submitted values inside the validator by UIInput#getSubmittedValue().

E.g.

<h:form>     <h:inputHidden id="foo" value="true">         <f:validator validatorId="fooValidator" />         <f:attribute name="input1" value="#{input1}" />         <f:attribute name="input2" value="#{input2}" />         <f:attribute name="input3" value="#{input3}" />     </h:inputHidden>     <h:inputText binding="#{input1}" value="#{bean.input1}" />     <h:inputText binding="#{input2}" value="#{bean.input2}" />     <h:inputText binding="#{input3}" value="#{bean.input3}" />     <h:commandButton value="submit" action="#{bean.submit}" />     <h:message for="foo" /> </h:form> 

(please note the value="true" on the hidden input; the actual value actually doesn't matter, but keep in mind that the validator won't necessarily be fired when it's null or empty, depending on the JSF version and configuration)

with

@FacesValidator(value="fooValidator") public class FooValidator implements Validator {      @Override     public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {         UIInput input1 = (UIInput) component.getAttributes().get("input1");         UIInput input2 = (UIInput) component.getAttributes().get("input2");         UIInput input3 = (UIInput) component.getAttributes().get("input3");         // ...                  Object value1 = input1.getSubmittedValue();         Object value2 = input2.getSubmittedValue();         Object value3 = input3.getSubmittedValue();         // ...     }  } 

If you declare the <h:inputHidden> after the to-be-validated components, then the values of the involved components are already converted and validated and you should obtain them by UIInput#getValue() or maybe UIInput#getLocalValue() (in case the UIInput isn't isValid()) instead.

See also:

  • Validator for multiple fields (JSF 1.2 targeted)

Alternatively, you can use 3rd party tags/components for that. RichFaces for example has a <rich:graphValidator> tag for this, Seam3 has a <s:validateForm> for this, and OmniFaces has several standard <o:validateXxx> components for this which are all showcased here. OmniFaces uses a component based approach whereby the job is done in UIComponent#processValidators(). It also allows customizing it in such way so that the above can be achieved as below:

<h:form>     <o:validateMultiple id="foo" components="input1 input2 input3" validator="#{fooValidator}" />     <h:inputText id="input1" value="#{bean.input1}" />     <h:inputText id="input2" value="#{bean.input2}" />     <h:inputText id="input3" value="#{bean.input3}" />     <h:commandButton value="submit" action="#{bean.submit}" />     <h:message for="foo" /> </h:form> 

with

@ManagedBean @RequestScoped public class FooValidator implements MultiFieldValidator {      @Override     public boolean validateValues(FacesContext context, List<UIInput> components, List<Object> values) {         // ...     } } 

The only difference is that it returns a boolean and that the message should be specified as message attribute in <o:validateMultiple>.

like image 109
BalusC Avatar answered Oct 12 '22 22:10

BalusC


Apache ExtVal was not mentioned here.

There are some cross validations in it (among other validations which might be useful):

https://cwiki.apache.org/confluence/display/EXTVAL/Property+Validation+Usage#PropertyValidationUsage-CrossValidation

like image 33
Jens Avatar answered Oct 12 '22 21:10

Jens