Как определить, действительно ли DateField в Vaadin 8

У меня есть:

DateField dateField = new DateField("Date");
Button submitButton = new Button("Submit");
submitButton.addClickListener(click -> handleClickListener());

где в handleClickListener() я хочу предотвратить отправку, если есть ошибка проверки в DateField. Я знаю, что могу использовать Binder, а затем binder.validate(), но у этой формы нет вспомогательного объекта, и мне нужна простая форма. Как я могу сделать что-то вроде:

if(!dateField.isValid())
   // no further processing
else
   // process

Я не могу найти какой-либо код в DateField, который позволяет проверить, действительно ли введенное значение. По-видимому, в Vaadin 7 вы могли бы !dateField.validate() вызвать исключение, но это уже не так...

Я также знаю, что можно сделать dateField.isEmpty() или проверить на нуль, но это не работает, потому что значение НЕ требуется. Другими словами, он может быть либо пустым, либо, если вы вводите значение, это должна быть действительная запись.


person Stephane Grenier    schedule 06.10.2017    source источник
comment
Как насчет использования Binder (vaadin.com/api/8.0.1 /com/vaadin/data/Binder.html)? Binder поставляется с такими методами, как validate() и isValid().   -  person Thibstars    schedule 06.10.2017
comment
Иногда Binder не работает. Например, у моей формы может не быть POJO и т. д., может быть, я просто использую форму, чтобы сделать быстрый расчет на этикетке и не хочу ничем ее подкреплять.   -  person Stephane Grenier    schedule 07.10.2017


Ответы (2)


Об этом спрашивали несколько раз, и, насколько я знаю, невозможно добавить валидаторы без связующего. Вы можете проверить этот ответ для подробного описания функции и резонанса.

Обсуждения также ведутся на форуме Vaadin и github, и два основных предложения — использовать связующее или прослушиватель изменения значения, когда вы вручную вызываете валидатор. Однако последнее решение, похоже, не работает, и я подозреваю, что это связано с тем, что событие изменения значения запускается только при изменении фактического значения, чего, вероятно, не происходит, когда вы вводите что-то недопустимое, но я не тратил много времени на расследование.

последнее предложение на github запрашивает binder.noBind() метод для облегчения этих случаев, но пока это не реализовано, вы можете использовать что-то похожее на приведенный ниже пример кода. Мне также не нравилась идея использования поля для привязки значения, поэтому я выбрал концепцию без сеттера и без геттера:

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
            };
        }
    }
}

Результат:

проверка поля даты с помощью связующего


Позднее обновление:

Я подумал еще немного, и если это приемлемо, вы можете отключить кнопку отправки, если значение равно null или возникает ошибка синтаксического анализа для недопустимого значения. Это можно легко реализовать с помощью ValueChangeListener и ErrorHandler, как показано ниже.

В качестве альтернативы вы можете сохранить сообщение об исключении в переменной, и когда вы нажмете кнопку, проверьте, есть ли сообщение об ошибке или значение равно 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);
    }
}

Результат:

проверка поля даты vaadin

person Morfic    schedule 06.10.2017
comment
Это очень близко к тому, что я сделал. В основном вы создаете поддельный POJO (или что-то подобное) для привязки к Binder, а затем используете проверку привязки при нажатии кнопки «Отправить». - person Stephane Grenier; 07.10.2017
comment
@StephaneGrenier Да, это в значительной степени идея, по крайней мере, на данный момент .... - person Morfic; 08.10.2017
comment
@StephaneGrenier Как насчет второго подхода? - person Morfic; 19.10.2017

Несмотря на то, что вы заявили, что не хотите использовать резервный объект, я бы все равно рекомендовал использовать Binder. Предоставленный класс No @Morfic, на мой взгляд, превосходен (я склонен повторно использовать его во многих реализациях проверки).

Итак, что бы я сделал, это добавить addStatusChangeListener в вашу подшивку и включить/отключить кнопку там:

binder.addStatusChangeListener(event -> {
            if (event.hasValidationErrors()) {
                submitButton.setEnabled(false);
            } else {
                submitButton.setEnabled(true);
            }
        });

Пропущено создание экземпляра объекта Binder, поскольку @Morfic уже предоставил хороший пример в своем ответе.

Причина, по которой я предлагаю использовать Binder, заключается в том, что Vaadin предлагает использовать его для проверки вам не нужно сложно поддерживать прослушиватели изменения значения, и вы можете легко расширить свою привязку с помощью новых Validator, если это потребуется позже. Возможно, в какой-то момент вы захотите привязать поле к объекту.

person Thibstars    schedule 20.10.2017