diff --git a/flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java b/flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java index 27d235af172..b4fe191301d 100644 --- a/flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java +++ b/flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java @@ -940,8 +940,8 @@ public BindingBuilder withValidator( Objects.requireNonNull(validator, "validator cannot be null"); Validator wrappedValidator = ((value, context) -> { - if (getBinder().isValidatorsDisabled() || - (binding != null && binding.isValidatorsDisabled())) { + if (getBinder().isValidatorsDisabled() || (binding != null + && binding.isValidatorsDisabled())) { return ValidationResult.ok(); } else { return validator.apply(value, context); @@ -1121,7 +1121,8 @@ public BindingImpl(BindingBuilderImpl builder, onValueChange = getField().addValueChangeListener( event -> handleFieldValueChange(event)); - if (getField() instanceof HasValidator) { + if (getBinder().isFieldsValidationStatusChangeListenerEnabled() + && getField() instanceof HasValidator) { HasValidator hasValidatorField = (HasValidator) getField(); onValidationStatusChange = hasValidatorField .addValidationStatusChangeListener( @@ -1425,7 +1426,8 @@ public boolean isValidatorsDisabled() { } @Override - public void setConvertBackToPresentation(boolean convertBackToPresentation) { + public void setConvertBackToPresentation( + boolean convertBackToPresentation) { this.convertBackToPresentation = convertBackToPresentation; } @@ -1543,6 +1545,8 @@ void setIdentity() { private boolean validatorsDisabled = false; + private boolean fieldsValidationStatusChangeListenerEnabled = true; + /** * Creates a binder using a custom {@link PropertySet} implementation for * finding and resolving property names for @@ -1961,7 +1965,7 @@ public void writeBean(BEAN bean) throws ValidationException { * {@code null} */ public void writeBeanAsDraft(BEAN bean) { - doWriteDraft(bean, new ArrayList<>(bindings),false); + doWriteDraft(bean, new ArrayList<>(bindings), false); } /** @@ -1981,7 +1985,7 @@ public void writeBeanAsDraft(BEAN bean) { * disable all Validators during write */ public void writeBeanAsDraft(BEAN bean, boolean forced) { - doWriteDraft(bean, new ArrayList<>(bindings),forced); + doWriteDraft(bean, new ArrayList<>(bindings), forced); } /** @@ -2090,12 +2094,12 @@ private BinderValidationStatus doWriteIfValid(BEAN bean, * disable validators during write if true */ @SuppressWarnings({ "unchecked" }) - private void doWriteDraft(BEAN bean, - Collection> bindings, boolean forced) { + private void doWriteDraft(BEAN bean, Collection> bindings, + boolean forced) { Objects.requireNonNull(bean, "bean cannot be null"); if (!forced) { - bindings.forEach(binding -> ((BindingImpl) binding) + bindings.forEach(binding -> ((BindingImpl) binding) .writeFieldValue(bean)); } else { boolean isDisabled = isValidatorsDisabled(); @@ -3202,7 +3206,7 @@ public void removeBinding(String propertyName) { /** * Control whether validators including bean level validators are * disabled or enabled globally for this Binder. - * + * * @param validatorsDisabled Boolean value. */ public void setValidatorsDisabled(boolean validatorsDisabled) { @@ -3212,10 +3216,34 @@ public void setValidatorsDisabled(boolean validatorsDisabled) { /** * Returns if the validators including bean level validators * are disabled or enabled for this Binder. - * + * * @return Boolean value */ public boolean isValidatorsDisabled() { return validatorsDisabled; } + + /** + * Control whether bound fields implementing {@link HasValidator} subscribe + * for field's {@code ValidationStatusChangeEvent}s and will + * {@code validate} upon receiving them. + * + * @param fieldsValidationStatusChangeListenerEnabled + * Boolean value. + */ + public void setFieldsValidationStatusChangeListenerEnabled( + boolean fieldsValidationStatusChangeListenerEnabled) { + this.fieldsValidationStatusChangeListenerEnabled = fieldsValidationStatusChangeListenerEnabled; + } + + /** + * Returns if the bound fields implementing {@link HasValidator} subscribe + * for field's {@code ValidationStatusChangeEvent}s and will + * {@code validate} upon receiving them. + * + * @return Boolean value + */ + public boolean isFieldsValidationStatusChangeListenerEnabled() { + return fieldsValidationStatusChangeListenerEnabled; + } } diff --git a/flow-data/src/test/java/com/vaadin/flow/data/binder/BinderValidationStatusChangeListenerTest.java b/flow-data/src/test/java/com/vaadin/flow/data/binder/BinderValidationStatusChangeListenerTest.java index d130af2d782..01e153d13d5 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/binder/BinderValidationStatusChangeListenerTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/binder/BinderValidationStatusChangeListenerTest.java @@ -64,6 +64,16 @@ public void fieldWithHasValidatorDefaults_bindIsCalled_addValidationStatusListen .addValidationStatusChangeListener(Mockito.any()); } + @Test + public void binderWithFieldsValidationStatusChangeListenerDisabled_bindIsCalled_noValidationStatusListenerIsCalled() { + binder.setFieldsValidationStatusChangeListenerEnabled(false); + TestHasValidatorDatePicker.DatePickerHasValidatorDefaults field = Mockito + .spy(TestHasValidatorDatePicker.DatePickerHasValidatorDefaults.class); + binder.bind(field, BIRTH_DATE_PROPERTY); + Mockito.verify(field, Mockito.never()) + .addValidationStatusChangeListener(Mockito.any()); + } + @Test public void fieldWithHasValidatorOnlyGetDefaultValidatorOverridden_bindIsCalled_addValidationStatusListenerIsCalled() { TestHasValidatorDatePicker.DataPickerHasValidatorGetDefaultValidatorOverridden field = Mockito @@ -102,6 +112,17 @@ public void fieldWithHasValidatorFullyOverridden_fieldValidationStatusChangesToF Assert.assertEquals(INVALID_DATE_FORMAT, componentErrors.get(field)); } + @Test + public void binderWithFieldsValidationStatusChangeListenerDisabled_fieldValidationStatusChangesToFalse_binderHandleErrorIsNotCalled() { + binder.setFieldsValidationStatusChangeListenerEnabled(false); + TestHasValidatorDatePicker.DataPickerHasValidatorOverridden field = new TestHasValidatorDatePicker.DataPickerHasValidatorOverridden(); + binder.bind(field, BIRTH_DATE_PROPERTY); + Assert.assertEquals(0, componentErrors.size()); + + field.fireValidationStatusChangeEvent(false); + Assert.assertEquals(0, componentErrors.size()); + } + @Test public void fieldWithHasValidatorFullyOverridden_fieldValidationStatusChangesToTrue_binderClearErrorIsCalled() { TestHasValidatorDatePicker.DataPickerHasValidatorOverridden field = new TestHasValidatorDatePicker.DataPickerHasValidatorOverridden();