Search code examples
validationjsfjsf-2.2composite-component

Override default validator of input in composite component


I'm developing a composite component with a default validator that may be used alongside a more restrictive custom validator. However, it didn't work as intented.

I boiled down the problem as below:

<h:inputText id="textId" value="#{bean.text}">
    <f:validateLength for="textId" maximum="10" />
    <f:validateLength for="textId" maximum="5" />
</h:inputText>

The validation for maximum=5 is not executed or the result is omitted, as only the maximum=10 rule results in proper feedback:

Text field: 1234567890123

searchForm:textId: Validation Error: Length is greater than allowable maximum of '10'

Text field: 1234567

passes

What is the reason behind this behavior? How can I achieve my requirement anyway?


Solution

  • from your comment, I assume, you have a component like this:

    <cc:interface >
        <cc:editableValueHolder name="text" targets="myText"  />
    </cc:interface>
    <cc:implementation>
        <h:inputText id="myText">
            <f:validateLength maximum="10" />
        </h:inputText>
    </cc:implementation>
    

    And you want to use it - assuming its called myInput - like this:

    <ns:myInput>
        <f:validateLength maximum="5" for="text" />
    </ns:myInput>
    

    hence, if no validateLength is given, your 10 should apply, else the other value, if it's more restrictive.

    I think it is by design, that you can only use ONE validator for a certain validation type. So, to overcome this issue you have 3 options:

    First, you could use a regex validator inside the component, like:

       <h:inputText id="myText">
            <f:validateRegex pattern=".{,10}" />
        </h:inputText>
    

    This would allow the component user to apply his own f:validateLength. But then ofc. he would no longer be able to apply his own f:validateRegex.

    Another Option would be, to make the component user able to disable the build-in validation with a component attribute. But this however would completly bypass your contraint of length 10 if the user decides to disable it.

    The best option (imho) would be to apply the maxLength as an own attribute, and validate that option against your contraint of max. 10 digits:

    <cc:interface >
        <cc:attribute name="maxLength" required="false" default="10"/>
    </cc:interface>
    <cc:implementation>
        <h:inputText id="myText">
            <f:validateLength maximum="#{(cc.attrs.maxLength > 10)? 10 : cc.attrs.maxLength}" />
        </h:inputText>
    </cc:implementation>
    

    Usage would now be:

    <ns:myInput maxLength="15">
        <!-- This will apply your contraint of 10 -->
    </ns:myInput>
    
    <ns:myInput maxLength="3">
        <!-- This will apply the component users constraint of 3 -->
    </ns:myInput>
    

    This also has the advantage, that the component user does not need to know about the actual name of the encapsuled editableValueHolder in order to apply a f:validateLength.

    Also think about, if it really makes sence to limit the maxLength inside your component. Components should be able to work for any use-case on the designed datatype, unless they control the appearence of the component, for instance column count, items per page and the like.