Search code examples
validationjsfprimefaceserror-messaging

How to avoid multiple Primefaces error messages when using multiple JSF validators at the same input field


I have one Primefaces p:inputText component with 2 JSF-validators. First one to check RegEx, second one to check miniumum and maximum length of the input field.

If the validation doesn't matches both validators, then I have the same validator message displayed twice in global messages.

This is my component:

<p:messages id="globalMsg" />

...
<p:inputText id="raRegEmail" 
                value="#{bean.emailAdres}"
                required="true"
                validatorMessage="#{i18nMsg['invalid_email']}"
                styleClass="w-full">
    <f:validateRegex pattern="#{bean.getRegEx('email')}" />
    <f:validateLength minimum="6" maximum="200"/>
</p:inputText>
<p:message id="raRegEmailMsg" for="raRegEmail" />

For example, an emailadres as "7777" fails both f:validateXXX, but there is only one possible validatorMessage in the component, which is displayed twice in global messages <p:messages/>.

Errormessages after validation

I would expect to have only one error message displayed.

How can I fixed it, so that only one global message is displayed?


Solution

  • To avoid displaying multiple error messages for a single input field when using multiple JSF validators, you can use a custom validator. A custom validator allows you to control the validation process and the error messages that are displayed.

    Here's an example of how you can create a custom validator:

    @FacesValidator("customEmailValidator")
    public class CustomEmailValidator implements Validator {
    private final String EMAIL_PATTERN = "^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$";
    
       @Override
       public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
           String email = value.toString();
    
           // Check if email is empty
           if (email.isEmpty()) {
               throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Email is required", null));
           }
    
           // Check if email matches the regex pattern
           if (!email.matches(EMAIL_PATTERN)) {
               throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Invalid email format", null));
           }
    
           // Check if email length is between 6 and 200
           if (email.length() < 6 || email.length() > 200) {
               throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Email length should be between 6 and 200 characters", null));
           }
       }
    }
    

    Now, you can then use this custom validator in your JSF component like this:

    <p:inputText id="raRegEmail" 
                   value="#{bean.emailAdres}"
                   required="true"
                   validatorMessage="#{i18nMsg['invalid_email']}"
                   styleClass="w-full">
       <f:validator validatorId="customEmailValidator" />
    </p:inputText>
    <p:message id="raRegEmailMsg" for="raRegEmail" />