Explorar el Código

Add isValid to Binder (#8274)

* Add isValid to Binder

isValid enables you to check the current validation
status of a given Binder, without firing events or invoking
handlers.

This patch also clarifies the javadocs of StatusChangeEvents'
hasValidationErrors.

* Throw in Binder.isValid if no bean is set and bean validators exist

* Add test cases to BinderTest
tags/8.0.0.rc1
Aleksi Hietanen hace 7 años
padre
commit
560d161540

+ 2
- 2
documentation/datamodel/datamodel-forms.asciidoc Ver fichero

@@ -375,8 +375,8 @@ We can use that event to make the save and reset buttons of our forms become ena
[source, java]
----
binder.addStatusChangeListener(event -> {
boolean isValid = !event.hasValidationErrors();
boolean hasChanges = binder.hasChanges();
boolean isValid = event.getBinder().isValid();
boolean hasChanges = event.getBinder().hasChanges();

saveButton.setEnabled(hasChanges && isValid);
resetButton.setEnabled(hasChanges);

+ 29
- 0
server/src/main/java/com/vaadin/data/Binder.java Ver fichero

@@ -1579,6 +1579,35 @@ public class Binder<BEAN> implements Serializable {
fireStatusChangeEvent(validationStatus.hasErrors());
return validationStatus;
}
/**
* Runs all currently configured field level validators, as well as all bean
* level validators if a bean is currently set with
* {@link #setBean(Object)}, and returns whether any of the validators
* failed.
*
* @return whether this binder is in a valid state
* @throws IllegalStateException
* if bean level validators have been configured and no bean is
* currently set
*/
public boolean isValid() {
if (getBean() == null && !validators.isEmpty()) {
throw new IllegalStateException(
"Cannot validate binder: "
+ "bean level validators have been configured "
+ "but no bean is currently set");
}
if (validateBindings().stream().filter(BindingValidationStatus::isError)
.findAny().isPresent()) {
return false;
}
if (getBean() != null && validateBean(getBean()).stream()
.filter(ValidationResult::isError).findAny().isPresent()) {
return false;
}
return true;
}

/**
* Validates the bindings and returns the result of the validation as a list

+ 8
- 7
server/src/main/java/com/vaadin/data/StatusChangeEvent.java Ver fichero

@@ -26,7 +26,7 @@ import com.vaadin.server.Setter;
* <p>
* The {@link Binder} status is changed whenever any of the following happens:
* <ul>
* <li>if it's bound and any of its bound field or select has been changed
* <li>if any of its bound fields or selects have been changed
* <li>{@link Binder#writeBean(Object)} or
* {@link Binder#writeBeanIfValid(Object)} is called
* <li>{@link Binder#readBean(Object)} is called
@@ -47,13 +47,14 @@ public class StatusChangeEvent extends EventObject {
private final boolean hasValidationErrors;

/**
* Create a new status change event for given {@code binder} using its
* current validation status.
* Create a new status change event for given {@code binder}, storing
* information of whether the change that triggered this event caused
* validation errors.
*
* @param binder
* the event source binder
* @param hasValidationErrors
* the binder validation status
* the validation status associated with this event
*/
public StatusChangeEvent(Binder<?> binder, boolean hasValidationErrors) {
super(binder);
@@ -61,10 +62,10 @@ public class StatusChangeEvent extends EventObject {
}

/**
* Gets the binder validation status.
* Gets the associated validation status.
*
* @return {@code true} if the binder has validation errors, {@code false}
* otherwise
* @return {@code true} if the change that triggered this event caused
* validation errors, {@code false} otherwise
*/
public boolean hasValidationErrors() {
return hasValidationErrors;

+ 27
- 2
server/src/test/java/com/vaadin/data/BinderBookOfVaadinTest.java Ver fichero

@@ -724,7 +724,7 @@ public class BinderBookOfVaadinTest {
AtomicBoolean eventIsFired = new AtomicBoolean(false);

binder.addStatusChangeListener(event -> {
boolean isValid = !event.hasValidationErrors();
boolean isValid = event.getBinder().isValid();
boolean hasChanges = event.getBinder().hasChanges();
eventIsFired.set(true);

@@ -782,7 +782,7 @@ public class BinderBookOfVaadinTest {
AtomicBoolean eventIsFired = new AtomicBoolean(false);

binder.addStatusChangeListener(event -> {
boolean isValid = !event.hasValidationErrors();
boolean isValid = event.getBinder().isValid();
boolean hasChanges = event.getBinder().hasChanges();
eventIsFired.set(true);

@@ -824,6 +824,31 @@ public class BinderBookOfVaadinTest {
verifyEventIsFired(eventIsFired);
}

@Test
public void statusChangeListener_multipleRequiredFields() {
Button saveButton = new Button();

binder.addStatusChangeListener(event -> {
boolean isValid = event.getBinder().isValid();
boolean hasChanges = event.getBinder().hasChanges();

saveButton.setEnabled(hasChanges && isValid);
});

binder.forField(field).asRequired("").bind(BookPerson::getLastName,
BookPerson::setLastName);
binder.forField(emailField).asRequired("").bind(BookPerson::getEmail,
BookPerson::setEmail);

Assert.assertFalse(saveButton.isEnabled());
field.setValue("not empty");
Assert.assertFalse(saveButton.isEnabled());
emailField.setValue("not empty");
Assert.assertTrue(saveButton.isEnabled());
field.clear();
Assert.assertFalse(saveButton.isEnabled());
}

private void verifyEventIsFired(AtomicBoolean flag) {
Assert.assertTrue(flag.get());
flag.set(false);

+ 52
- 0
server/src/test/java/com/vaadin/data/BinderTest.java Ver fichero

@@ -494,4 +494,56 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
Assert.assertFalse(ageField.isReadOnly());
}

@Test
public void isValidTest_bound_binder() {
binder.forField(nameField)
.withValidator(
Validator.from(
name -> !name.equals("fail field validation"),
""))
.bind(Person::getFirstName, Person::setFirstName);

binder.withValidator(
Validator.from(person -> !person.getFirstName()
.equals("fail bean validation"), ""));

binder.setBean(item);

Assert.assertTrue(binder.isValid());

nameField.setValue("fail field validation");
Assert.assertFalse(binder.isValid());

nameField.setValue("");
Assert.assertTrue(binder.isValid());

nameField.setValue("fail bean validation");
Assert.assertFalse(binder.isValid());
}

@Test
public void isValidTest_unbound_binder() {
binder.forField(nameField)
.withValidator(Validator.from(
name -> !name.equals("fail field validation"), ""))
.bind(Person::getFirstName, Person::setFirstName);

Assert.assertTrue(binder.isValid());

nameField.setValue("fail field validation");
Assert.assertFalse(binder.isValid());

nameField.setValue("");
Assert.assertTrue(binder.isValid());
}

@Test(expected = IllegalStateException.class)
public void isValidTest_unbound_binder_throws_with_bean_level_validation() {
binder.forField(nameField).bind(Person::getFirstName,
Person::setFirstName);
binder.withValidator(Validator.from(
person -> !person.getFirstName().equals("fail bean validation"),
""));
binder.isValid();
}
}

Cargando…
Cancelar
Guardar