1

Mojarra 2.1

I need to stop validating an input value after one of the validators failed. Here is what I tried:

<h:inputText id="filterName" value="#{bean.name}" >
    <f:validator validatorId="simpleNameValidator" />
    <f:validator binding="#{customValidator}" disabled="#{facesContext.validationFailed()}"/>
</h:inputText>

The validators:

public class SimpleNameValidator implements Validator{

    private static final int MAX_LENGHT = 32; 

    @Override
    public void validate(FacesContext context, UIComponent component,
            Object value) throws ValidatorException {
        String v = (String) value;
        FacesMessage msg;
        if(v.equals(StringUtils.EMPTY)){
            msg = new FacesMessage("Name is empty");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }
        if(v.length() >= MAX_LENGHT){
            msg = new FacesMessage("Name is too long"));
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }

    }
}

and

public class CustomValidator implements Validator{

    private NameService nameService;

    @Override
    public void validate(FacesContext context, UIComponent component,
            Object value) throws ValidatorException {
        String name = nameService.getName((String) value);
        if(name != null) {
            FacesMessage msg = new FacesMessage("The name already exists");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(msg);
        }
    }

    public NameService getNameService() {
        return nameService;
    }

    public void setNameService(NameService nameService) {
        this.nameService = nameService;
    }

}

But it didn't work. I didn't understand why it didn't, because I explcitly specified the disabled attribute of the second validator. So, it must not have been even applied, because the first one failed. Maybe I misunderstood the validationFailed's purpose...

Couldn't you explain that behavior and how to fix that?

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • 1
    what if you remove the () from `disabled="facesContext.validationFailed()"` Now you call the 'validationFailed()' method on the faces context, which sets it and returns void. By removing the (), you call isValidationFailed(), the getter... – Kukeltje Aug 07 '15 at 11:39
  • 1
    In addition to the custom validator ensuring the uniqueness among names, it appears that you are trying to simulate what the `required` and the `` validators already do. If so, then simply adopt them. – Tiny Aug 07 '15 at 12:24

1 Answers1

3

The <f:validator disabled> attribute is evaluated during view build time, at that moment when the validator is about to be attached to the component. It's not evaluated right before performing the validation.

You can work around this one of following ways:

  • Inside validate() method, just check if component is valid via UIInput#isValid().

    if (!((UIInput) component).isValid()) {
        return;
    }
    
    // ...
    
  • Use <o:validator> of JSF utility library OmniFaces. It supports deferred evaluation of EL in all of its attributes. Here's an example with an improved check in disabled attribute.

    <o:validator binding="#{customValidator}" disabled="#{not component.valid}"/>
    

    The #{component} refers to the current UIComponent instance, which is in case of a <h:inputXxx> component an instance of UIInput which has thus a isValid() property.


Unrelated to the concrete problem, the requireness and length validation can be done with just required="true" or <f:validateRequired>, and the <f:validateLength> respectively. In case you intend to customize the messages, there are ways via requiredMessage and validatorMessage attributes, or a custom <message-bundle>.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • __there are ways via requiredMessage and validatorMessage attributes, or a custom .__ In [one of your answers](http://stackoverflow.com/questions/19027022/custom-jsf-validator-message-for-a-single-input-field) you wrote that it's possible to just inherit from the validator class. Is that considered acceptable way to customize message? Or specifying the message-bundle is the preffered way to do that? – St.Antario Aug 08 '15 at 04:02
  • If you can, specify the ``. – BalusC Aug 08 '15 at 07:29