问题
I have:
DateField dateField = new DateField("Date");
Button submitButton = new Button("Submit");
submitButton.addClickListener(click -> handleClickListener());
where in handleClickListener()
I want to prevent a submit if there is a validation error in the DateField
. I know I can use a Binder and then binder.validate()
but this form has no backing object and I just want a simple form. How can I do something like:
if(!dateField.isValid())
// no further processing
else
// process
I can't find any code within the DateField
that allows checking to see if the entered in value is valid. Apparently in Vaadin 7 you could !dateField.validate() which would throw an exception but this is no longer appears to be the case...
I also know it's possible to do dateField.isEmpty()
or test for null but this doesn't work because a value is NOT required. In other words it can be either empty, or if you put in a value then it must be a valid entry.
回答1:
This has been asked several times, and as far as I know it's not possible to add validators without the binder. You can check this answer for a comprehensive description of the feature and resoning.
There are also discussions on the Vaadin forum and github, and the 2 main suggestions are using a binder, or a value change listener where you manually call a validator. However, the latter solution does not seem to work and I suspect that's because a value change event is triggerd only when the actual value changes, which probably does not happen when you type something invalid, but I did not spend much time investigating.
The latest suggestion on github requests a binder.noBind()
method to facilitate these cases, but until that is implemented you could use something similar to the below code sample. I also hated the idea of using a field to bind the value to, so I went with a no setter & no getter concept:
public class DateFieldWithValidator extends VerticalLayout {
public DateFieldWithValidator() {
// date field with binder
Binder<LocalDate> binder = new Binder<>();
DateField dateField = new DateField("Date");
binder.forField(dateField)
.asRequired("Please select a date")
.bind(No.getter(), No.setter());
// validity status
TextField validityField = new TextField("Status:", "N/A");
validityField.setReadOnly(true);
validityField.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS);
validityField.setWidth("100%");
// submit button
Button submitButton = new Button("Submit");
submitButton.addClickListener(event -> {
BinderValidationStatus<LocalDate> status = binder.validate();
if (status.isOk()) {
validityField.setValue("OK: " + dateField.getValue().toString());
} else {
validityField.setValue("KO: " + status.getValidationErrors().stream().map(ValidationResult::getErrorMessage).collect(Collectors.joining(",")));
}
});
addComponents(dateField, submitButton, validityField);
}
// convenience empty getter and setter implementation for better readability
public static class No {
public static <SOURCE, TARGET> ValueProvider<SOURCE, TARGET> getter() {
return source -> null;
}
public static <BEAN, FIELDVALUE> Setter<BEAN, FIELDVALUE> setter() {
return (bean, fieldValue) -> {
//no op
};
}
}
}
Result:
Later update:
I've been thinking some more, and if it's acceptable, you could disable the submit button if the value is null or a parsing error occurs for an invalid value. This can be easily implemented with a ValueChangeListener
and an ErrorHandler
like below.
Alternatively, you can save the exception message in a variable, and when you click the button check if either there is an error message or the value is null, in this order because if you input an invalid date, the field's value will be set to null.
public class DateFieldWithValidator extends VerticalLayout {
public DateFieldWithValidator() {
DateField dateField = new DateField("Date");
Button submitButton = new Button("Submit");
submitButton.setEnabled(false);
submitButton.addClickListener(event -> Notification.show("Selected date: " + dateField.getValue()));
dateField.setRequiredIndicatorVisible(true);
dateField.setErrorHandler(event -> submitButton.setEnabled(false));
dateField.addValueChangeListener(event -> submitButton.setEnabled(event.getValue() != null));
addComponents(dateField, submitButton);
}
}
Result:
回答2:
Even though you stated you don't want to use a backing object, I would recommend the use of Binder
anyway. The No
class @Morfic provided is excellent in my opinion (I tend to reuse this in many validation implementations).
So what I would do is add a addStatusChangeListener
on your binder and enable/disable the button there:
binder.addStatusChangeListener(event -> {
if (event.hasValidationErrors()) {
submitButton.setEnabled(false);
} else {
submitButton.setEnabled(true);
}
});
Omitted the instantiation of the Binder
object since @Morfic provided a good example in his answer already.
The reason why I suggest the use of Binder
is because Vaadin suggests to use it for validation, you won't need hard to maintain value change listeners and you could easily expand your binding with new Validator
s if so required later on. Maybe you will want to bind the field to an object at one point after all.
来源:https://stackoverflow.com/questions/46598157/how-to-determine-if-a-datefield-is-valid-in-vaadin-8