在使用Turbolinks的Rails 5.1应用程序中,我在我的提交按钮中添加了一个data-disable-with属性,因此在单击时,该按钮将被禁用,以防止意外多次提交数据.这在许多情况下都很有用.
问题是在使用内置UJS帮助程序(data-remote = true)通过AJAX提交的表单上,单击提交按钮时,它不会保持禁用状态.它最初被禁用,但在下一页加载之前会快速重新启用.这违背了数据禁用行为的要点,因为它使意外的表单重新提交成为可能.
有没有办法在加载新页面之前保持表单按钮被禁用?
这是表格:
<%= simple_form_for( resource,as: resource_name,url: session_path(resource_name),html: { class: "large",autocomplete: "on" },remote: true ) do |f| %> <%= f.input( :email,placeholder: "Email address",label: false,autofocus: true ) %> <%= f.input(:password,placeholder: "Password",label: false) %> <%= f.button( :submit,"Sign in",class: "ui fluid large teal submit button","data-disable-with": "Signing in..." ) %> <% end %>
解决方法
怎么了?
>表格已提交
> rails-ujs禁用该按钮(data-disable-with behavior)
>表单请求成功
> rails-ujs重新启用按钮
> turbolinks-rails向重定向位置发出请求(可能是一个缓慢的位置,使按钮处于启用状态)
解
我们需要在第4步之后重新禁用该按钮.为此,我们将监听ajax:success事件,并使用setTimeout禁用它.这确保了在Rails完成它之后它将被禁用. (您可以使用requestAnimationFrame而不是setTimeout,但它不受广泛支持.)
为了防止按钮被缓存在禁用状态,我们将在缓存之前重新启用它. (注意使用一个而不是on来防止before-cache处理程序执行多次.)
我注意到你使用的是jQuery和jquery-ujs,所以我将在下面的代码中使用这些库中的函数.将其包含在主JavaScript文件中的某处.
jQuery的UJS
;(function () { var $doc = $(document) $doc.on('submit','form[data-remote=true]',function () { var $form = $(this) var $button = $form.find('[data-disable-with]') if (!$button.length) return $form.on('ajax:complete',function () { // Use setTimeout to prevent race-condition when Rails re-enables the button setTimeout(function () { $.rails.disableFormElement($button) },0) }) // Prevent button from being cached in disabled state $doc.one('turbolinks:before-cache',function () { $.rails.enableFormElement($button) }) }) })()
rails-ujs / jQuery
;(function () { var $doc = $(document) $doc.on('ajax:send',function () { // Use setTimeout to prevent race-condition when Rails re-enables the button setTimeout(function () { $button.each(function () { Rails.disableElement(this) }) },function () { $button.each(function () { Rails.enableElement(this) }) }) }) })()
rails-ujs / vanilla JS
Rails.delegate(document,'ajax:send',function (event) { var form = event.target var buttons = form.querySelectorAll('[data-disable-with]') if (!buttons.length) return function disableButtons () { buttons.forEach(function (button) { Rails.disableElement(button) }) } function enableButtons () { buttons.forEach(function (button) { Rails.enableElement(button) }) } function beforeCache () { enableButtons() document.removeEventListener('turbolinks:before-cache',beforeCache) } form.addEventListener('ajax:complete',function () { // Use setTimeout to prevent race-condition when Rails re-enables the button setTimeout(disableButtons,0) }) // Prevent button from being cached in disabled state document.addEventListener('turbolinks:before-cache',beforeCache) })
请注意,这将禁用按钮,直到下一页加载所有数据远程表单并带有data-disable-with按钮.您可能希望更改jQuery选择器以仅将此行为添加到选定的表单.
希望有所帮助!