How to determine if a DateField is valid in Vaadin 8

允我心安 提交于 2019-12-11 07:00:01

问题


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 Validators 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!