在使用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选择器以仅将此行为添加到选定的表单.
希望有所帮助!