Search code examples
javascriptruby-on-railsrails-ujsform-with

Rails ujs and remote form, How to stop form submission the programmatically submit form


I am using rails form_with as a remote form. Before submission I want to display a custom confirm box with a dynamic message. After the box is indeed confirmed I want to eventually submit the form. I came up with 'ajax:beforeSend' event handler :

const form = document.getElementById('assign_sessions_to_employees')
form.addEventListener(
  'ajax:beforeSend',
  (event) => {
    event.preventDefault();
    swal.fire({
      title: 'Are you sure ?',
      text: `You are about to spend ${expectedExpenditure()} credits.`,
      showCancelButton: true,
    }).then((result) => {
      if (result.isConfirmed) {
        console.log('submitting')
        Rails.fire(form, 'submit');
      }
    })
  }
)

This works fine, however when I run Rails.fire(form, 'submit');, when I eventually want to submit the form this retriggers 'ajax:beforeSend' and I get stuck in the loop.

What would be the correct way to achieve this behavior with form_with and rails ujs ?


Solution

  • If you use a function declaration (aka a named function) you can remove the event handler with EventTarget.removeEventListener():

    function handleConfirmation(event){
      let form = event.target;
      event.preventDefault();
      swal.fire({
         title: 'Are you sure ?',
         text: `You are about to spend ${expectedExpenditure()} credits.`,
         showCancelButton: true,
      }).then((result) => {
         if (result.isConfirmed) {
           console.log('submitting');
           form.removeEventListener('ajax:beforeSend', handleConfirmation);
           Rails.fire(form, 'submit');
         }
        })
      }
    }
    const form = document.getElementById('assign_sessions_to_employees')
    form.addEventListener('ajax:beforeSend', handleConfirmation);
    

    Another alternative is to just set a data attribute in your event handler:

    const form = document.getElementById('assign_sessions_to_employees')
    form.addEventListener(
      'ajax:beforeSend',
      (event) => {
        if (event.target.dataset.confirmed) { return };
        event.preventDefault();
        swal.fire({
          title: 'Are you sure ?',
          text: `You are about to spend ${expectedExpenditure()} credits.`,
          showCancelButton: true,
        }).then((result) => {
          if (result.isConfirmed) {
            console.log('submitting');
            form.dataset.confirmed = true;
            Rails.fire(form, 'submit');
          }
        })
      }
    )