Syllz
Syllz

Reputation: 340

jQuery: Form Submission - Multiple Event Handlers

Currently having some issues with jQuery Form Submissions in my project.

My project contains a general jQuery Code which prevents form double submissions (e.g. someone clicks the 'submit' button multiple times).

//prevent multiple form submissions
jQuery.fn.preventDoubleSubmission = function () {
    $(document).on('submit', this, function (e) {
        let $form = $(this);
        if ($form.data('submitted') === true) {
            e.preventDefault();
        } else {
            $form.data('submitted', true);
        }
    });
    return this;
};


$(function () {
    $('form').preventDoubleSubmission();
});

This code is included into every single page - so every form should be 'protected'.

For some specific forms I need to check some values before they are submitted - and show a confirm box, if some values are missing (e.g. Are you sure you want to submit this form without value X?)

Here's the code:

$(document).on('submit', 'form[name="article"]', function (e) {
    e.preventDefault();
    let form = this;
    let $form = $(form);
    let $category = $form.find('select#article_category'); //get category

    if ($category.length && !$category.val()) { //check if category is selected
        $.confirm({ //jquery confirm plugin
            title: "Are you sure?",
            content: "Value X is missing - continue?",
            buttons: {
                confirm: {
                    action: function () {
                        $form.off('submit');
                        form.submit();
                    }
                }
            }
        });
    } else {
        $form.off('submit');
        form.submit();
    }
});

So basically, if the user tries to submit the form, but the value X is missing, there will be a Yes/No Popup first - if the value exists, the form will be submitted right away.

Problem: When I want to submit the form, I call $form.off('submit'); to remove the event handler and submit afterwards with form.submit();. Sadly this also removes my preventDoubleSubmission event handler, which allows double submissions again.

Is there a way to fix my issue? Thanks

Upvotes: 3

Views: 3911

Answers (3)

Syllz
Syllz

Reputation: 340

So I finally figured out a relatively ok solution for me. However it is very simple and I might stick with it.

//form submission function
function submitForm(form) {
    let $form = $(form);
    let $submit = $form.find('button[type=submit]'); //find submit button

    $submit.attr('disabled', true); //disable button = prevent double submission
    form.submit(); //submit form
}

//submission for every form but not .form-confirm
$(document).on('submit', 'form:not(.form-confirm)', function (e) {
    e.preventDefault();
    submitForm(this); //call function
});

$(document).on('submit', 'form[name="article"]', function (e) {
    e.preventDefault();
    let form = this;
    let $form = $(form);

    let $category = $form.find('select#article_category'); //get category

    if ($category.length && !$category.val()) { //check if category is selected
        $.confirm({
            title: "Are you sure?",
            content: "Value X is missing - continue?",
            buttons: {
                confirm: {
                    action: function () {
                        submitForm(form); //call function
                    }
                }
            }
        });
    } else {
        submitForm(form); //call function
    }
});

So how does it work?

Basically I just disable the submit button after submitting (=prevent double submissions). I added a class called form-confirm to the specific form which the popup should show, so the general rule does not work there. I always use preventDefault and use form.submit() to submit right away in my code.

Upvotes: 1

DarkPatronusLinX
DarkPatronusLinX

Reputation: 397

Below is a code snippet with a correct solution. There were multiple issues with your original approach, highlighted below the snippet. Better to run this snippet in a different code playground, where action with javascript work, e.g. JSFiddle.

//prevent multiple form submissions
function submitOnce (e, $form) {
  alert('submitted = ' + $form.data('submitted'));
  if ($form.data('submitted') === true) {
    e.preventDefault();
    alert('Double-submission prevented!');
  } else {
    $form.data('submitted', true);
    alert('Double-submission param saved');
  }
}


$(document).on('submit', 'form[name="article"]', function (e) {
		let form = this;
    let $form = $(form);
    
    let $category = $form.find('select#article_category'); //get category

    if ($category.length && !$category.val()) { //check if category is selected
    
      if ( confirm("Are you sure?") ){
        submitOnce(e,$form);
      }
      else {
      	e.preventDefault();
      }
        
    } else {
        submitOnce(e,$form);
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form name="article" action="javascript:alert('Form submitted!');">
  <select id="article_category" name="select1">
    <option></option>
    <option>option1</option>
    <option>option2</option>
  </select>
  <input type="submit" />
</form>

edit: adding explanations

$form.off() would work if you would bind 'submit' event handler directly on the form element, but in both cases handlers are registered on the document.

Calling form.submit() is not necessary, since we are already in a submit handler, hence submit already called. We just need to prevent submissions to continue.

Better is to have just one submit handler, and deal with double submits there.

e.preventDefault(); has to be just in the else clause for a non-confirmed case and in submitOnce(). You had it at the beginning of the main handler, but it was useless there, since form.submit() was called again inside, and this call does not prevent the default.

My approach is not bullet-proof and serves just as a demonstration of what needed to be changed.

Upvotes: 2

Kalimah
Kalimah

Reputation: 11437

One approach is to use a normal span with a click event. Once it is clicked you can disable it (using a class for example) and then submit form. This approach allows you to control form submission without the need of extra coding.

See this example:

$submitBtn = jQuery(".submit");
$form = jQuery("form[name='article']");

$submitBtn.on("click", function() {
  if (jQuery(this).hasClass("disabled"))
    return;

  let $category = $form.find('.name'); //get value

  if ($category.length && !$category.val()) { //check if value is set
    $.confirm({ //jquery confirm plugin
      title: "Are you sure ?",
      content: 'Value x is missing - continue ?',
      buttons: {
        confirm: {
          action: function() {
            $form.submit();
            $submitBtn.addClass("disabled");
          }
        },
        cancel: function() {
          //$.alert('canceled');
        }
      }
    });

    return;
  }

  $submitBtn.addClass("disabled");
  $form.submit();

});
form {
  border: 1px solid rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  width: 200px;
}

form input {
  margin-bottom: 0.5rem;
  padding: 0.3rem;
  border-radius: 3px;
  border: 1px solid gray;
}

form .submit {
  padding: 0.3rem 1rem;
  cursor: pointer;
  border-radius: 3px;
  background-color: rgba(0, 0, 0, 0.1);
  text-align: center;
  transition: all 0.3s;
}

form .submit.disabled {
  opacity: 0.5;
  cursor: default;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.4/jquery-confirm.min.js"></script>

<form action="" name='article'>
  First name:<br>
  <input type="text" name="firstname" value="My First Name" class='name'>
  <br> Last name:<br>
  <input type="text" name="lastname" value="My Last Name">
  <br><br>
  <span class='submit'>Submit</span>
</form>

Upvotes: 1

Related Questions