How to check in a Validator if the value has been changed?
default-value, jsf, validation
Solution
The submitted value is just available as `value` argument in the `validate()` implementation.
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Object oldValue = ((UIInput) component).getValue();
if (value != null ? value.equals(oldValue) : oldValue == null) {
// Value has not changed.
return;
}
// Continue validation here.
}
An alternative is to design the `Validator` as a `ValueChangeListener`. It'll then only be invoked when the value has really changed. It's somewhat hacky, but it does the job you really need.
<h:inputText ... valueChangeListener="#{uniqueValueValidator}" />
or
<h:inputText ...>
<f:valueChangeListener binding="#{uniqueValueValidator}" />
</h:inputText>
with
@ManagedBean
public class UniqueValueValidator implements ValueChangeListener {
@Override
public void processValueChange(ValueChangeEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
UIInput input = (UIInput) event.getComponent();
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// Validate newValue here against DB or something.
// ...
if (invalid) {
input.setValid(false);
context.validationFailed();
context.addMessage(input.getClientId(context),
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Please enter unique value", null));
}
}
}
Note that you cannot throw a `ValidatorException` there, that's why need to manually set both the component and faces context to invalid and manually add the message for the component. The `context.validationFailed()` will force JSF to skip the update model values and invoke action phases.
Problem
I know I can get the old value through `UIInput#getValue()`. But in many cases where the field is bound to a bean value I want to get the default value that I don't need to validate if the input equals the default value. This is very usefull if a certain field has a unique constraint and you have a editing form. Validation will always fail since in a check constraint method it will always find its own value thus validating to false. One way would be to pass that default value as an attribute using `<f:attribute>` and check inside the validator. But is there an easier built-in way?