简体   繁体   English

vaadin 交叉表单验证失败,因为 bean 未绑定

[英]vaadin cross form validation fails as bean not bound

<vaadin.version>22.0.7</vaadin.version> <vaadin.version>22.0.7</vaadin.version>

I have built a vaadin edit form with an attached Save button.我已经构建了一个带有附加保存按钮的 vaadin 编辑表单。 When the user clicks 'Save' I want to validate the form and then save the validated data to the bean.当用户单击“保存”时,我想验证表单,然后将验证后的数据保存到 bean 中。

This works as expected.这按预期工作。

The problem comes when I went to add in cross field validation.当我去添加跨字段验证时,问题就来了。 In this case I want to validate that a start/end date pair are in the correct order.在这种情况下,我想验证开始/结束日期对的顺序是否正确。

The problem is that when I add the form validator, vaadin starts throwing exceptions when I call validate.问题是当我添加表单验证器时,vaadin 在我调用验证时开始抛出异常。

@Override
    public void bindFields(CrudFieldBinder<DiscountCode> binder)
    {
        binder.forField(this.discountCode).asRequired("Please enter the unique Discount Code.").bind(
                DiscountCode::getDiscountCode,
                DiscountCode::setDiscountCode);

        binder.forField(this.startDate).asRequired("Please enter a Start Date.").bind(DiscountCode::getStartDate,
                DiscountCode::setStartDate);

        binder.forField(this.endDate).asRequired("Please enter an End Date.")
                .bind(DiscountCode::getEndDate,
                        DiscountCode::setEndDate);

        binder.withValidator(new DateRangeValidator());
        
    }

I've tried a few variations all with the same result.我尝试了几种变体,结果都是一样的。 Here is the latest iteration:这是最新的迭代:

    protected void saveEdits(E currentEntity) {
        try
        {
            binder.writeBean(currentEntity);
        }
        catch (ValidationException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // this line throws the below error
        BinderValidationStatus<E> status = binder.validate();
 }

The call to writeBean runs without error but the call to binder.validate() fails with:对 writeBean 的调用运行没有错误,但对 binder.validate() 的调用失败并显示:

java.lang.IllegalStateException: Cannot validate binder: bean level validators have been configured but no bean is currently set
    at com.vaadin.flow.data.binder.Binder.validate(Binder.java:2479) ~[flow-data-9.0.8.jar:9.0.8]
    at com.vaadin.flow.data.binder.Binder.validate(Binder.java:2463) ~[flow-data-9.0.8.jar:9.0.8]
... EditorFormLayout.saveEdits(EditorFormLayout.java:92) ~[classes/:?]

This seems to suggest that form level validation only works if you make a call to setBean, however my understanding is the call to setBean will result in the form autosaving rather than waiting for the user to click the save button.这似乎表明表单级验证仅在调用 setBean 时有效,但我的理解是调用 setBean 将导致表单自动保存,而不是等待用户单击保存按钮。

I don't believe there is a supported method for doing this.我不相信有支持的方法可以做到这一点。

I've raised a feature request here: https://github.com/vaadin/platform/issues/2868我在这里提出了一个功能请求: https://github.com/vaadin/platform/issues/2868

Here is my hack that relies on overloading the binder and making the validation method think a bean is bound.这是我的 hack,它依赖于重载活页夹并使验证方法认为 bean 已绑定。


import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.BinderValidationStatus;


public class MyBinder<E> extends Binder<E>
{
    public MyBinder()
    {

    }

    /**
     * Apparently when doing cross field validation by calling
     * binder.withValidator there is no way to the list of errors back
     * due to the following issue.
     *   https://github.com/vaadin/platform/issues/2868
     *   
     *   Which essentially says that unless you are using setBean you can't
     *   do cross form validation.
     *   
     *   This code caches the bean sent to the binder when readBean is called
     *   and then uses that bean to fake a bound bean during validation.
     *   
     */
    private boolean validating = false;
    private E bean;

    @Override
    public void readBean(E bean)
    {
        this.bean = bean;
        super.readBean(bean);
    }

    @Override
    public void setBean(E bean)
    {
        throw new RuntimeException("The MyBinder only works with read/writeBean");
    }

    @Override
    public E getBean()
    {
        if (validating)
        {
            return bean;
        }
        /// this call should always return null as setBean hasn't been
        // called but we do this try to reduce the likelihood of this overload
        // causing problems if someone accicentially uses this class
        // when using setBean.
        return super.getBean();
    }

    @Override
    public BinderValidationStatus<E> validate()
    {
        try
        {
            // force getBean to return a bean during validation.
            validating = true;
            return super.validate();
        }
        finally
        {
            validating = false;
        }

    }

}```

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM