How to save submit buttons on remote forms until the next page loads

In my Rails 5.1 application using Turbolinks, I added an attribute data-disable-withto my submit buttons, so when I click it, the button will be disabled to prevent data from being accidentally sent multiple times. In many cases, this works great.

The problem is that in forms that are submitted via AJAX using the built-in UJS ( data-remote=true) helpers , when you click the submit button, it does not stay disabled. It is initially disabled, but then activated again until the next page loads. This defeats the behavior point data-disable-withas it allows for accidental resubmission of the form.

Can I disable the form button before loading a new page?

Here is the form:

<%= 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 %>

. An example of correctly submitting a submit button when clicked, but then re-enabling before loading a new page

+7
3

?

  • ​​
  • rails-ujs ( data-disable-with)
  • rails-ujs
  • turbolinks-rails ( , )

4. ajax:success setTimeout. , , Rails . ( requestAnimationFrame setTimeout, .)

, . ( one, on, .)

, 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', '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 () {
        $button.each(function () { Rails.disableElement(this) })
      }, 0)
    })

    // Prevent button from being cached in disabled state
    $doc.one('turbolinks:before-cache', function () {
      $button.each(function () { Rails.enableElement(this) })
    })
  })
})()

rails-ujs/vanilla JS

Rails.delegate(document, 'form[data-remote=true]', '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-remote data-disable-with. jQuery, .

, !

+9

FYI: Rails " rails-ujs XHR ".

PR, : # 1 # 2.

, .

+2

how to submit form data and disable the button.

<form method="post" enctype="multipart/form-data" action="action.php">
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title"> submit and disabled button </h3>
        </div>
        <div class="panel-body">
            {% csrf_token %}
            <div class="form-group">
                <label>Montant</label>
                <input type="number" name="montant" id="montant" required/>
            </div>
            <div class="form-group">
                <center><span id="msgError"></span></center>
            </div>
        </div>
    </div>
<div class="form-group">
    <button type="submit" name="save" id="save">Enregistrer</button>
</div>

</form>'

<script>

    $(document).ready(function(){
        var count = 0;
        $('#save').click(function(){
           var montant = $('#montant').val();
           if (montant!=''){
               count++;
               var montant = $('#montant').val();
               // first click data are sending
               if (count == 1){
                  return true;
               }else{
               // disable button 
                  $('#msgError').text('Merci de patienter...');
                  $('#msgError').css('color', 'blue');
                  $('#save').attr('disabled', 'disabled');
               }
           }
        });
   });
</script>
0
source

Source: https://habr.com/ru/post/1687806/


All Articles