From 3c52491a5b44456f94777e6cec71af2a1a70ae46 Mon Sep 17 00:00:00 2001 From: "Márcio P. Dantas" Date: Mon, 26 Mar 2018 17:44:28 +0300 Subject: Added method asRequired with a custom required validator to BindingBuilder. (#10724) --- server/src/main/java/com/vaadin/data/Binder.java | 30 ++++++- .../src/test/java/com/vaadin/data/BinderTest.java | 92 ++++++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) (limited to 'server/src') diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index f9e076e13f..360daa73bf 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -728,6 +728,23 @@ public class Binder implements Serializable { */ public BindingBuilder asRequired( ErrorMessageProvider errorMessageProvider); + + /** + * Sets the field to be required and delegates the required check to a custom validator. + * This means two things: + *
    + *
  1. the required indicator will be displayed for this field
  2. + *
  3. the field value is validated by customRequiredValidator
  4. + *
+ * + * @see HasValue#setRequiredIndicatorVisible(boolean) + * @param customRequiredValidator + * validator responsible for the required check + * @return this binding, for chaining + * @since + */ + public BindingBuilder asRequired( + Validator customRequiredValidator); } /** @@ -885,11 +902,18 @@ public class Binder implements Serializable { @Override public BindingBuilder asRequired( ErrorMessageProvider errorMessageProvider) { + return asRequired( + Validator.from( + value -> !Objects.equals(value, field.getEmptyValue()), + errorMessageProvider)); + } + + @Override + public BindingBuilder asRequired( + Validator customRequiredValidator) { checkUnbound(); field.setRequiredIndicatorVisible(true); - return withValidator( - value -> !Objects.equals(value, field.getEmptyValue()), - errorMessageProvider); + return withValidator(customRequiredValidator); } /** diff --git a/server/src/test/java/com/vaadin/data/BinderTest.java b/server/src/test/java/com/vaadin/data/BinderTest.java index 0163b65b51..5ca469011c 100644 --- a/server/src/test/java/com/vaadin/data/BinderTest.java +++ b/server/src/test/java/com/vaadin/data/BinderTest.java @@ -30,6 +30,7 @@ import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.TextField; +import org.apache.commons.lang.StringUtils; public class BinderTest extends BinderTestBase, Person> { @@ -501,6 +502,97 @@ public class BinderTest extends BinderTestBase, Person> { assertTrue(textField.isRequiredIndicatorVisible()); } + @Test + public void setRequired_withCustomValidator_fieldGetsRequiredIndicatorAndValidator() { + TextField textField = new TextField(); + textField.setLocale(Locale.CANADA); + assertFalse(textField.isRequiredIndicatorVisible()); + + BindingBuilder binding = binder.forField(textField); + assertFalse(textField.isRequiredIndicatorVisible()); + AtomicInteger invokes = new AtomicInteger(); + + Validator customRequiredValidator = (value, context) -> { + invokes.incrementAndGet(); + if (StringUtils.isBlank(value)) { + return ValidationResult.error("Input is required."); + } + return ValidationResult.ok(); + }; + binding.asRequired(customRequiredValidator); + assertTrue(textField.isRequiredIndicatorVisible()); + + binding.bind(Person::getFirstName, Person::setFirstName); + binder.setBean(item); + assertNull(textField.getErrorMessage()); + assertEquals(0, invokes.get()); + + textField.setValue(" "); + ErrorMessage errorMessage = textField.getErrorMessage(); + assertNotNull(errorMessage); + assertEquals("Input is required.", errorMessage.getFormattedHtmlMessage()); + // validation is done for all changed bindings once. + assertEquals(1, invokes.get()); + + textField.setValue("value"); + assertNull(textField.getErrorMessage()); + assertTrue(textField.isRequiredIndicatorVisible()); + } + + @Test + public void setRequired_withCustomValidator_modelConverterBeforeValidator() { + TextField textField = new TextField(); + textField.setLocale(Locale.CANADA); + assertFalse(textField.isRequiredIndicatorVisible()); + + Converter stringBasicPreProcessingConverter = new Converter() { + @Override + public Result convertToModel(String value, ValueContext context) { + if (StringUtils.isBlank(value)) { + return Result.ok(null); + } + return Result.ok(StringUtils.trim(value)); + } + + @Override + public String convertToPresentation(String value, ValueContext context) { + if (value == null) { + return ""; + } + return value; + } + }; + + AtomicInteger invokes = new AtomicInteger(); + Validator customRequiredValidator = (value, context) -> { + invokes.incrementAndGet(); + if (value == null) { + return ValidationResult.error("Input required."); + } + return ValidationResult.ok(); + }; + + binder.forField(textField) + .withConverter(stringBasicPreProcessingConverter) + .asRequired(customRequiredValidator) + .bind(Person::getFirstName, Person::setFirstName); + + binder.setBean(item); + assertNull(textField.getErrorMessage()); + assertEquals(0, invokes.get()); + + textField.setValue(" "); + ErrorMessage errorMessage = textField.getErrorMessage(); + assertNotNull(errorMessage); + assertEquals("Input required.", errorMessage.getFormattedHtmlMessage()); + // validation is done for all changed bindings once. + assertEquals(1, invokes.get()); + + textField.setValue("value"); + assertNull(textField.getErrorMessage()); + assertTrue(textField.isRequiredIndicatorVisible()); + } + @Test public void validationStatusHandler_onlyRunForChangedField() { TextField firstNameField = new TextField(); -- cgit v1.2.3