143

I have a form that, when submitted, I need to do some additional processing before it should submit the form. I can prevent default form submission behavior, then do my additional processing (it's basically calling Google Maps API and adding a few hidden fields to the form) -- and then I need the form to submit.

Is there a way to "prevent default", then some point later "continue default?"

1

11 Answers 11

90

Use jQuery.one()

Attach a handler to an event for the elements. The handler is executed at most once per element per event type

$('form').one('submit', function(e) {
    e.preventDefault();
    // do your things ...

    // and when you done:
    $(this).submit();
});

The use of one prevent also infinite loop because this custom submit event is detatched after the first submit.

Sign up to request clarification or add additional context in comments.

6 Comments

it will submit after clicking again :(
Probably you will face with infinite loop
Infinite loop, the function should be .on not .one
To prevent infinite loop, first unbind the form event and submit it. $(this).unbind(); $(this).submit();
This should have been voted the right answer
|
59

When you bind the .submit() event to the form, and you do the things you want to do before returning (true), these things happen prior to the actual submission.

For example:

$('form').submit(function(){
    alert('I do something before the actual submission');
    return true;
});

Simple example

Another example on jquery.com: http://api.jquery.com/submit/#entry-examples

6 Comments

are you saying that the form will not submit until all code before the "return true;" statement is executed?
Yes that is exactly what the submit() function does.
It's not a good example becayse it's synchronyous. What if the stuff I need to do is async call? So the case is "click submit -> do async stuff and dont' submit the form -> in async callback fill some fields in the form -> submit the form from the callback"
What about run some async jQuery code?! Will work too?
this works great for me. I use it to control things before submitting and if things are not right I use "return false". I have looked for this solution for a day. thanks alot.
|
32

I would just do:

 $('#submiteButtonID').click(function(e){
     e.preventDefault();
     //do your stuff.
     $('#formId').submit();
 });

Call preventDefault at first and use submit() function later, if you just need to submit the form

6 Comments

don't involve logic inside your click event handler. delegate it to others responsibility.
This assumes the sure will click a button. What if the user just hits the "enter" button from within the form? That will also submit the form. So, it's probably not a good idea to rely on the submit button getting clicked.
i was just giving an example of a click... since there was no related codes mentioned on the question....
In any case, the snippet you gave will only work should the user click a button. That's not how forms work. Any other suggestions?
bind the click, prevent its default and trigger the submit button click
|
24
      $('#myform').on('submit',function(event){
        // block form submit event
        event.preventDefault();

        // Do some stuff here
        ...

        // Continue the form submit
        event.currentTarget.submit();
  });

4 Comments

TypeError: event.currentTarget.submit is not a function
in my case i had to use event.target.submit()
None of them (target or currentTarget) are working.
Its should be api.jquery.com/event.currentTarget. Unless your target is not a form element because only forms can submit
20

Using this way You will do a endless Loop on Your JS. to do a better way you can use the following

var on_submit_function = function(evt){
    evt.preventDefault(); //The form wouln't be submitted Yet.
    (...yourcode...)

    $(this).off('submit', on_submit_function); //It will remove this handle and will submit the form again if it's all ok.
    $(this).submit();
}

$('form').on('submit', on_submit_function); //Registering on submit.

I hope it helps! Thanks!

2 Comments

the best way actually, variation with async function - gist.github.com/BjornMelgaard/8ba0ee9d07c20dd8c8b3550c9df3e9ef
@bjornmelgaard I have to remember that the async is non standard.
11

This is, IMHO, the most generic and robust solution (if your actions are user-triggered, eg 'user clicks on a button'):

  • the first time a handler is called check WHO triggered it:
    • if a user tiggered it - do your stuff, and then trigger it again (if you want) - programmatically
    • otherwise - do nothing (= "continue default")

As an example, note this elegant solution to adding "Are you sure?" popup to any button just by decorating a button with an attribute. We will conditionally continue default behavior if the user doesn't opt out.

1. Let's add to every button that we want an "are you sure" popup a warning text:

<button class="btn btn-success-outline float-right" type="submit"  ays_text="You will lose any unsaved changes... Do you want to continue?"                >Do something dangerous</button>

2. Attach handlers to ALL such buttons:

$('button[ays_text]').click(function (e, from) {
    if (from == null) {  // user clicked it!
        var btn = $(this);
        e.preventDefault();
        if (confirm() == true) {
            btn.trigger('click', ['your-app-name-here-or-anything-that-is-not-null']);
        }
    }
    // otherwise - do nothing, ie continue default
});

That's it.

1 Comment

Great answer! I didn't know that you could pass an extra argument to .trigger()
5

With jQuery and a small variation of @Joepreludian's answer above:

Important points to keep in mind:

  • .one(...) instead on .on(...) or .submit(...)
  • named function instead of anonymous function since we will be referring it within the callback.

$('form#my-form').one('submit', function myFormSubmitCallback(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var $this = $(this);
    if (allIsWell) {
        $this.submit(); // submit the form and it will not re-enter the callback because we have worked with .one(...)
    } else {
        $this.one('submit', myFormSubmitCallback); // lets get into the callback 'one' more time...
    }
});

You can change the value of allIsWell variable in the below snippet to true or false to test the functionality:

$('form#my-form').one('submit', function myFormSubmitCallback(evt){
  evt.stopPropagation();
  evt.preventDefault();
  var $this = $(this);
  var allIsWell = $('#allIsWell').get(0).checked;
  if(allIsWell) {
    $this.submit();
  } else {
    $this.one('submit', myFormSubmitCallback);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="/" id="my-form">
  <input name="./fname" value="John" />
  <input name="./lname" value="Smith" />
  <input type="submit" value="Lets Do This!" />
  <br>
  <label>
    <input type="checkbox" value="true" id="allIsWell" />
    All Is Well
  </label>
</form>

Good Luck...

2 Comments

Are you sure stopPropagation is needed here? Also you can create a name less function (remove myFormSubmitCallback)
@MelroyvandenBerg, stopPropagation is not needd but we did that to avoid the event from propagating to other elements. You can remove it if you want the event to propagate - the core functionality of this solution will not be affected. And the reason we have used a named function is so that we can refer it within the function recursively.
4

In a pure Javascript way, you can submit the form after preventing default.

This is because HTMLFormElement.submit() never calls the onSubmit(). So we're relying on that specification oddity to submit the form as if it doesn't have a custom onsubmit handler here.

var submitHandler = (event) => {
  event.preventDefault()
  console.log('You should only see this once')
  document.getElementById('formId').submit()
}

See this fiddle for a synchronous request.


Waiting for an async request to finish up is just as easy:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('before')
  setTimeout(function() {
    console.log('done')
    document.getElementById('formId').submit()
  }, 1400);
  console.log('after')
}

You can check out my fiddle for an example of an asynchronous request.


And if you are down with promises:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('Before')
    new Promise((res, rej) => {
      setTimeout(function() {
        console.log('done')
        res()
      }, 1400);
    }).then(() => {
      document.getElementById('bob').submit()
    })
  console.log('After')
}

And here's that request.

2 Comments

Is there a generic way in just plain javascript, not jquery or any libraries, modules, etc, to execute the "default action" of the specific triggered event after preventing default and executing your code? uh, delayDefault?
@jdmayfield Perhaps just put the default action code into a function. Then you can use it as both the default action and a delayed action after preventing the default.
3

"Validation injection without submit looping":

I just want to check reCaptcha and some other stuff before HTML5 validation, so I did something like that (the validation function returns true or false):

$(document).ready(function(){
   var application_form = $('form#application-form');

   application_form.on('submit',function(e){

        if(application_form_extra_validation()===true){
           return true;
        }

        e.preventDefault();

   });
});

Comments

1

You can use e.preventDefault() which will stop the current operation.

than you can do$("#form").submit();

 $('#form').submit(function (e)
{
    return !!e.submit;
});
if(blabla...)
{...
}
else
{
    $('#form').submit(
    {
        submit: true
    });
}

1 Comment

this is very confusing for me.. won't this just going around and around?
0
$('form').on('submit.mySecondarySubmit', function(e){
    
    $(this).off(e); // removes this event
    
    $.get('someurl', function(res){
        
        // some result
        
        // continue with original submit and original button target and propagation
        $(e.currentTarget).trigger(e.type, e.target);
    });

    return false; // stops bubbling and propagation
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.