vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
620 stars 167 forks source link

Vaadin 24 not showing validation error message on EmailField #17319

Open egloffmark opened 1 year ago

egloffmark commented 1 year ago

Description of the bug

I tried to follow the documentation tutorial to create a FormComponent with Binder and standard Validation for an email field. See here https://vaadin.com/docs/latest/binding-data/components-binder-validation

But when I configure the binder with EmailValidator it does not show the error message. The passed error message at the time the validation is empty.

My Form Component:

public class BackendUserForm extends FormLayout { 

 Binder<User> binder = new BeanValidationBinder<>(User.class);
 EmailField email = new EmailField("Email");

  public BackendUserForm() {
      ...
       binder.forField(email)
        .withValidator(new EmailValidator("No valid email address"))
        .bind(User::getEmail, User::setEmail);
      ...
      add(email);
  }
}

Debugging the issue I see that in DefaultBinderValidationErrorHandler the error message is empty, so it looks like that it has not been taken over from the EmailValidator.

public class DefaultBinderValidationErrorHandler

    public void handleError(HasValue<?, ?> field, ValidationResult result) {
        if (field instanceof HasValidation) {
            HasValidation fieldWithValidation = (HasValidation) field;
            fieldWithValidation.setInvalid(true);
            fieldWithValidation.setErrorMessage(result.getErrorMessage());
        }
        setErrorTheme(field, result);
    }

The problem at the EmailFieldseems to be related to the underlying TextFieldValidationSupport and that there no error message can be set and may overload another validator

final class TextFieldValidationSupport implements Serializable {
 ...
        final boolean valueViolatePattern = value != null && !value.isEmpty()
                && pattern != null && !pattern.matcher(value).matches();
        if (valueViolatePattern) {
            return ValidationResult.error("");    // Here the empty error message is passed over
        }

        return ValidationResult.ok();
}

Workaround is to add an own status handler or to use instead the TextField instead of the EmailField.

      TextField email = new TextField("Email");

       binder.forField(email)
        .withValidator(new EmailValidator("No valid email address"))
        .bind(User::getEmail, User::setEmail);

// OR  for EmailField

    EmailField email = new EmailField("Email");

    binder.forField(email)
        .withValidationStatusHandler(statusChange -> {
            if(!binder.isValid()){
                log.info("Email address is invalid");
                email.setErrorMessage("Email address is invalid");
            }
        })
        .bind(User::getEmail, User::setEmail);

Expected behavior

There should be an easy way to show and/or customize the error message in case the email address is invalid or you adding a second validator without specifying a custom handler

Minimal reproducible example

  1. Take the Vaadin Flow CRM Demo app (Link)
  2. Add a Email Validator to the ContactForm component
  3. Run the application and change the email address to invalid value

Versions

knoobie commented 1 year ago

Known limitation (at the moment) as described in the upgrading guide to 24 for fields with custom frontend validations - like the EmailField. If you wanna have full flexibility, use the TextField instead of the EmailField. Other than that nothing has to be changed and your validation is correctly utilized and the error message is shown.

egloffmark commented 1 year ago

Ok thank you, seems to be related to the known "bug" #4618

mshabarov commented 1 year ago

I'm confused, even if it's a known limitation, the example above was taken from Vaadin docs. So at least the documentation needs a mention about this limitation in https://vaadin.com/docs/latest/binding-data/components-binder-validation or show a working code example.