• cdi
  • components
  • contexts
  • converters
  • eventlisteners
  • exceptionhandlers
  • facesviews
  • filters
  • functions
  • managedbeans
  • push
  • resourcehandlers
  • scripts
  • servlets
  • taghandlers
  • utils
  • validators
  • viewhandlers
-
  • converter
  • enableRestorableView
  • ignoreValidationFailed
  • importConstants
  • importFunctions
  • massAttribute
  • methodParam
  • skipValidators
  • tagAttribute
  • validator
  • viewParamValidationFailed

The <o:validator> is a taghandler that extends the standard <f:validator> tag family with support for deferred value expressions in all attributes. In other words, the validator attributes are not evaluated anymore on a per view build time basis, but just on every access like as with UI components and bean properties. This has among others the advantage that they can be evaluated on a per-iteration basis inside an iterating component, and that they can be set on a custom validator without needing to explicitly register it in a tagfile.

Usage

When you specify for example the standard <f:validateLongRange> by validatorId="javax.faces.LongRange", then you'll be able to use all its attributes such as minimum and maximum as per its documentation, but then with the possibility to supply deferred value expressions.

<o:validator validatorId="javax.faces.LongRange" minimum="#{item.minimum}" maximum="#{item.maximum}" />

The validator ID of all standard JSF validators can be found in their javadocs. First go to the javadoc of the class of interest, then go to VALIDATOR_ID in its field summary and finally click the Constant Field Values link to see the value.

It is also possible to specify the validator message on a per-validator basis using the message attribute. Any "{0}" placeholder in the message will be substituted with the label of the referenced input component. Note that this attribute is ignored when the parent component has already validatorMessage specified.

<o:validator validatorId="javax.faces.LongRange" minimum="#{item.minimum}" maximum="#{item.maximum}"
    message="Please enter between #{item.minimum} and #{item.maximum} characters" />

Demo

In the below first demo, it was the intent to use <f:validateLongRange> as follows:

 <f:validateLongRange minimum="#{question.minimum}" maximum="#{question.maximum}" />

But this fails hard as the minimum and maximum values are set during view build time instead of during processing the validation. The #{question} is not available during view build time and thus both minimum and maximum will default to 0 (for a background explanation, check this Stack Overflow answer). It works as intuitively expected with the <o:validator> as it allows a render time evaluation of attributes.

For another related use case, checkout the <o:converter> showcase page.

Further, the <o:validator> also allows setting the validation message on a per-validator basis by the message attribute. This is not possible with <f:validator> and the validatorMessage attribute of the parent input component applies to all validators. Note that the message attribute of <o:validator> has no effect when the validatorMessage attribute of the parent input component has already been set.

Demo

With f:validateLongRange in each row - fails!

Enter value between 1 and 9
Enter value between 5 and 10
Enter value between 3 and 7

With o:validator in each row - works!

Enter value between 1 and 9
Enter value between 5 and 10
Enter value between 3 and 7

Set validator message on a per-validator basis

Demo source code
<h3>With f:validateLongRange in each row - fails!</h3>
<h:form>
    <h:dataTable value="#{validatorBean.questions}" var="question">
        <h:column>
            Enter value between #{question.minimum} and #{question.maximum}
        </h:column>
        <h:column>
            <h:inputText id="input" value="#{question.answer}" required="true" requiredMessage="Fill out the value!">
                <f:validateLongRange minimum="#{question.minimum}" maximum="#{question.maximum}" />
            </h:inputText>
        </h:column>
        <h:column>
            <h:message for="input" />
        </h:column>
    </h:dataTable>
    <h:commandButton value="Submit">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:form>

<hr />

<h3>With o:validator in each row - works!</h3>
<h:form>
    <h:dataTable value="#{validatorBean.questions}" var="question">
        <h:column>
            Enter value between #{question.minimum} and #{question.maximum}
        </h:column>
        <h:column>
            <h:inputText id="input" value="#{question.answer}" required="true" requiredMessage="Fill out the value!">
                <o:validator validatorId="javax.faces.LongRange" minimum="#{question.minimum}" maximum="#{question.maximum}" message="Invalid value!" />
            </h:inputText>
        </h:column>
        <h:column>
            <h:message for="input" />
        </h:column>
    </h:dataTable>
    <h:commandButton value="Submit">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:form>

<hr />

<h3>Set validator message on a per-validator basis</h3>
<h:form>
    <h:messages />
    <h:dataTable binding="#{table}" value="#{validatorBean.entities}" var="entity">
        <h:column>
            <c:set var="label" value="Input #{table.rowIndex + 1}" />
            <o:outputLabel for="input" value="#{label}" />
        </h:column>
        <h:column>
            <h:inputText id="input" value="#{entity.value}" required="true" requiredMessage="#{label} is required">
                <o:validator validatorId="javax.faces.Length" minimum="5" message="{0} must be at least 5 chars" />
                <o:validator validatorId="javax.faces.RegularExpression" pattern="\\d+" message="{0} must contain digits only" /><!-- Fails in Apache EL (Tomcat/TomEE/etc), use \d+ instead. -->
            </h:inputText>
        </h:column>
    </h:dataTable>
    <h:commandButton value="Submit">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:form>
Documentation & Sources

VDL documentation

API documentation

Java source code