“disableOnClick”按钮在Vaadin 14中的可靠性。

huangapple go评论68阅读模式
英文:

reliability of Button "disableOnClick" in Vaadin 14

问题

我正在使用 Vaadin 14,在用户双击按钮时,为了避免多次发送请求,我在 Button 实例上调用了 setDisableOnClick(true)

但是对于某些按钮来说,仅此还不够:该按钮仍然可以被多次点击。在 Chrome 开发工具中检查 DOM,我可以看到这些按钮的 disableonclick 属性已设置如下:

“disableOnClick”按钮在Vaadin 14中的可靠性。

我怀疑这可能与调用事件处理程序的顺序有关(应先调用禁用处理程序,然后再调用发送请求的处理程序)。

我不想在服务器端设置布尔值来检查是否已执行操作。是否有其他选项在点击后可靠地立即禁用按钮?

英文:

I'm using Vaadin 14 and to avoid sending requests multiple times when a user double-clicks a button instead of just once, I'm calling setDisableOnClick(true) on the Button instance.

For some buttons this is not enough: the button can be still clicked multiple times. When inspecting the dom in Chrome devtools, I can see that the disableonclick property is set for these buttons:

“disableOnClick”按钮在Vaadin 14中的可靠性。

I suspect it's an issue with the order in which event handlers are called (the one to disable should be called before the one to send the request).

I'd rather not set a Boolean on the server side to check whether the action has been performed. Is there another option to reliably disable the button immediately after clicking?

答案1

得分: 3

这似乎是一个 Vaadin 的 bug。它不起作用的情况是当按钮位于一个被关闭然后重新打开的 Dialog 中。在调用 setDisableOnClick(true) 时,它们会使用一个从服务器端添加事件监听器的方法来进行处理:

/**
 * 初始化客户端禁用,以便在点击时禁用,即使服务器端处理需要一些时间。
 */
private void initDisableOnClick() {
    if (!disableOnClickConfigured) {
        getElement().executeJs("var disableEvent = function () {"
                + "if($0.getAttribute('disableOnClick')){"
                + " $0.setAttribute('disabled', 'true');" + "}" + "};"
                + "$0.addEventListener('click', disableEvent)");
        disableOnClickConfigured = true;
    }
}

当按钮被分离然后重新连接时,此事件处理程序就会消失。

不幸的是,在重新打开对话框后再次调用 setDisableOnClick(true) 是无效的,因为 disableOnClickConfigured 已经设置为 true,所以此代码将被跳过。

我看到三个选项:

  1. 当按钮被重新连接(对话框重新打开)时,通过反射将私有字段 disableOnClickConfigured 重置为 false,然后再次调用 setDisableOnClick(true)
  2. 将添加客户端事件监听器的代码复制并在按钮被重新连接时执行它。
  3. 通过替换按钮为新按钮,甚至每次打开时创建一个全新的 Dialog 实例,来避免这个问题。

我选择了最后一个选项。Dialog 是一个 Spring bean,所以我使用了 Prototype 作用域,并使用 ObjectFactory 进行注入,在调用 open 之前获取一个新的实例。

英文:

This seems to be a Vaadin bug. The cases where it doesn't work are when the buttons are in a Dialog that gets closed and then reopened. When you call setDisableOnClick(true), they're using a hack to add the event listener from the server side:

/**
 * Initialize client side disabling so disabled if immediate on click even
 * if server-side handling takes some time.
 */
private void initDisableOnClick() {
    if (!disableOnClickConfigured) {
        getElement().executeJs("var disableEvent = function () {"
                + "if($0.getAttribute('disableOnClick')){"
                + " $0.setAttribute('disabled', 'true');" + "}" + "};"
                + "$0.addEventListener('click', disableEvent)");
        disableOnClickConfigured = true;
    }
}

When the button is detached and re-attached, this event handler is gone.

Unfortunately calling setDisableOnClick(true) again after re-opening the dialog won't help, since disableOnClickConfigured will already be set to true so this code will be skipped.

I see three options:

  1. When the button gets re-attached (dialog gets reopened), reset private field disableOnClickConfigured to false through reflection and then call setDisableOnClick(true) again.
  2. Copy the code to add the client-side event listener and execute it when the button gets re-attached.
  3. Avoid the problem by replacing the button with a new one or even create whole a new Dialog instance each time it is opened.

It's the last option I chose to go with. The Dialog was a Spring bean so I'm using Prototype scope and inject it with an ObjectFactory, then get a new instance before calling open.

huangapple
  • 本文由 发表于 2020年8月28日 21:14:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/63634513.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定