Vaadin Flow DateTimePicker 在 CRUD 中变脏

Vaadin Flow DateTimePicker dirty inside CRUD

我正在将 com.vaadin.flow.component.datetimepicker.DateTimePicker 添加到 com.vaadin.flow.component.crud.Crud。这似乎总是将 CRUD 标记为脏。我注意到使用 com.vaadin.flow.component.datepicker.DatePicker 时一切都很好。此问题仅适用于 DateTimePicker。我该如何应对?

DateTimePicker dtp = new DateTimePicker("When");
dtp.setStep(Duration.ofMillis(1));
// ...
binder.bind(dtp, new ValueProvider<MyEvent, LocalDateTime>() {
    @Override
    public LocalDateTime apply(final MyEvent source) {
        return source.getWhen();
    }
}, ...

因此,DateTimePicker 以毫秒为单位,提供 LocalDateTime 值。

稍后编辑: 我进一步研究了 DateTimePicker.setPresentationValue(LocalDateTime) 实现,发现一些 JavaScript 正在执行:

datePicker.getElement().executeJs("this.dispatchEvent(new CustomEvent('change', { bubbles: true }));");

难道是这个?不幸的是,我不熟悉 Vaadin 的内部结构,所以不确定为什么在那里需要它。

我在其他组件上也遇到过相同的行为(例如:EnhancedDateTimePicker and Autocomplete)。在某些情况下,即使值根本没有更改,也会从客户端触发 ValueChangeEvent。这会使该字段变脏并使用活页夹这会产生 binder.hasChanges() returns true.

我已经制定了一个解决方法,即创建一个包含该组件的两个实例的自定义组件。一个是隐藏的(不可见的),只有当可见的值实际发生变化时才会更新。从活页夹(和任何其他外部)的角度来看,它是提供值和事件的隐藏组件。

这里是 EnhancedDateTimePicker:

public class DateTimeSelection extends HorizontalLayout implements 
        HasValue<AbstractField.ComponentValueChangeEvent<EnhancedDateTimePicker, LocalDateTime>, LocalDateTime> {

    private EnhancedDateTimeField hiddenDateTimeField = new EnhancedDateTimeField("");
    private EnhancedDateTimeField visibleDateTimeField = new EnhancedDateTimeField("");

    public DateTimeSelection() {
        visibleDateTimeField.addValueChangeListener(event -> {
            if (!ObjUtils.eq(event.getValue(), hiddenDateTimeField.getValue())) {
                hiddenDateTimeField.setValue(event.getValue());
            }
        });
        visibleDateTimeField.setWidthFull();
        add(visibleDateTimeField);
    }

    public DateTimeSelection(String label) {
        this();
        setLabel(label);
    }

    public String getLabel() {
        return visibleDateTimeField.getLabel();
    }

    public void setLabel(String label) {
        visibleDateTimeField.setLabel(label);
    }

    @Override
    public void setValue(LocalDateTime localDateTime) {
        hiddenDateTimeField.setValue(localDateTime);
        visibleDateTimeField.setValue(localDateTime);
    }

    @Override
    public LocalDateTime getValue() {
        return hiddenDateTimeField.getValue();
    }

    @Override
    public LocalDateTime getEmptyValue() {
        return hiddenDateTimeField.getEmptyValue();
    }

    @Override
    public Optional<LocalDateTime> getOptionalValue() {
        return hiddenDateTimeField.getOptionalValue();
    }

    @Override
    public boolean isEmpty() {
        return hiddenDateTimeField.isEmpty();
    }

    @Override
    public void clear() {
        hiddenDateTimeField.clear();
        visibleDateTimeField.clear();
    }

    @Override
    public void setReadOnly(boolean b) {
        visibleDateTimeField.setReadOnly(b);
    }

    @Override
    public boolean isReadOnly() {
        return visibleDateTimeField.isReadOnly();
    }

    @Override
    public void setRequiredIndicatorVisible(boolean b) {
        visibleDateTimeField.setRequiredIndicatorVisible(b);
    }

    @Override
    public boolean isRequiredIndicatorVisible() {
        return visibleDateTimeField.isRequiredIndicatorVisible();
    }

    @Override
    public Registration addValueChangeListener(ValueChangeListener<? super AbstractField.ComponentValueChangeEvent<EnhancedDateTimePicker, LocalDateTime>> valueChangeListener) {
        return hiddenDateTimeField.addValueChangeListener(valueChangeListener);
    }
}

请参阅 https://github.com/vaadin/flow-components/issues/1043。您应该能够通过适当的修复将项目的 pom.xml 更改为 pick-up v 14.7.1 版本的时间选择器流组件。