Search code examples
jsfmethodsvalidationcomposite-component

validator method not work in the JSF custom composite components


JSF custom composite components input.xhtml

<cc:interface>
    <cc:attribute name="validator"/>
</cc:interface>

<cc:implementation>
    <h:inputText validator="#{cc.attrs.validator}"/>
</cc:implementation>

*.xhtml

<l:input value = ... validator="#{testValidator.validator}"/>

java code

@ManagedBean

public class TestValidator {

    public void validator(FacesContext context, UIComponent component, Object value) throws ValidatorException {
         System.out.println("Call validator");
    }
}

PropertyNotFoundException:

validator="#{testValidator.validator}": The class 'TestValidator' does not have the property 'validator'.

How to solve this problem? my final way:


Solution

  • This is indeed not going to work. In order to attach a validator to an input component specified by the composite, you need to register the input component as a <cc:editableValueHolder> in the <cc:interface> first.

    <cc:interface>
        <cc:editableValueHolder name="yourInputName" targets="yourInputId" />
    </cc:interface>
    <cc:implementation>
        <h:inputText id="yourInputId" ... />
    </cc:implementation>
    

    This way, any <f:validator for="yourInputName"> nested in the composite component declaration will be applied to the desired input component.

    <l:input>
        <f:validator validatorId="myValidator" for="yourInputName" />
    </l:input>
    

    You'll only need to replace the tight coupled validator method by a real standalone Validator implementation.

    @FacesValidator("myValidator")
    public class MyValidator implements Validator {
        // ...
    }
    

    Note: the standard JSF validators like <f:validateLength>, <f:validateRequired>, etc have all also a for attribute for this purpose.