39

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Jonathan S. Fisher
  • 8,189
  • 6
  • 46
  • 84
  • 3
    Since I've posted this question... a few alternatives have come up. First, Omnifaces: http://code.google.com/p/omnifaces/ Second: JSF2.2 will support this when it's released – Jonathan S. Fisher Jun 19 '12 at 15:04

2 Answers2

64

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:


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>.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • You can also use RichFaces graphValidator http://richfaces-showcase.appspot.com/richfaces/component-sample.jsf?demo=graphValidator – Joshua Davis Dec 14 '11 at 18:04
  • @Joshua: or JSR303 bean validation. – BalusC Dec 14 '11 at 18:04
  • @BalusC: Yep. Or SeamFaces form validator http://docs.jboss.org/seam/3/faces/latest/reference/en-US/html/components.html#validateForm Currently this is my favorite. – Joshua Davis Dec 14 '11 at 21:43
  • 1
    @BalusC I tried this technique and when I throw a `ValidatorException` from inside the `validate()` method of the hidden input, I do not see the error message in the screen . If I make it a regular input , I see the error message in the screen. How can I have the error messages to be applied alongside the component which is causing the validation to fail? – Geek Mar 18 '13 at 12:03
  • @Geek: The message in the thrown `ValidatorException` will by default be associated with the component which triggered the validation which is in your case thus the hidden input. Just add a `` to get it to show up in there. Or manually add the message to the context on desired client ID and manually mark both the component and context as invalid. See also e.g. http://stackoverflow.com/questions/14012225/jsf-validation-in-action-phase/14012684#14012684 and source code of the OmniFaces validator components which does essentially exactly the same as answered here. – BalusC Mar 18 '13 at 12:10
  • @BalusC If I add hidden inputtextwithin a panelgrid, it disrupts the alignment of other component following hidden inputtext. How do I add hidden inputtext yet dont disrupt the alignment of other component? – Azfar Niaz Aug 20 '14 at 06:05
  • @Azfar: just put it outside grid? – BalusC Aug 20 '14 at 06:19
  • @BalusC, I placed it outside the grid managed to process both grid and hidden input. Thanks for the help. – Azfar Niaz Aug 20 '14 at 14:53
2

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

Jens
  • 6,243
  • 1
  • 49
  • 79