sialcasa / mvvmFX

an Application Framework for implementing the MVVM Pattern with JavaFX
Apache License 2.0
489 stars 105 forks source link

Validation for/with null-Values #599

Closed svedie closed 4 years ago

svedie commented 4 years ago

Hello,

in my view I have an optional e-mail address field. For this field I have implemented an ValidationVisualizer and an Validator. This works fine, if I enter an email or let the field empty.

The problem is, when I open the view for a new entry, then the email field is marked as an error until I enter some character and delete it or enter the correct email address.

How can implement the validator that he also ignores the "null"-value in the StringProperty.

Email Validator class:

public class EMailValidator extends ObservableRuleBasedValidator {

  private static final Pattern SIMPLE_EMAIL_REGEX = Pattern
      .compile("^$|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}");

  public EMailValidator(ObservableValue<String> source) {
    ResourceBundle resourceBundle = ResourceBundle.getBundle("bundle");
    addRule(ObservableRules.matches(source, SIMPLE_EMAIL_REGEX),
        ValidationMessage.error(resourceBundle.getString("validation.error.email")));
  }
}
manuel-mauky commented 4 years ago

Hi,

in this case I would use a FunctionBasedValidator instead of ObservableRuleBasedValidator. It should work like this (I haven't tested though):

public class EMailValidator extends FunctionBasedValidator<String> {
    private static final ResourceBundle resourceBundle = ResourceBundle.getBundle("bundle");

    private static final Pattern SIMPLE_EMAIL_REGEX = Pattern
            .compile("^$|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}");

    private static final Function<String, ValidationMessage> validationFunction = (input) -> {
        if(input == null) {
            // null is valid so we return null as result.
            return null;
        } else {
            if(SIMPLE_EMAIL_REGEX.matcher(input).matches()){
                return null;
            } else {
                return ValidationMessage.error(resourceBundle.getString("validation.error.email"));
            }
        }
    };

    public EMailValidator(ObservableValue<String> source) {
        super(source, validationFunction);
    }
}

The FunctionBasedValidator takes a function that takes the input value and returns null for a valid input or a ValidationMessage for errors. This way you have more power to decide when something is valid or not. See also here for more information about it.

svedie commented 4 years ago

It works as expected!

Thank you again. I have also added the example into the wiki.