7

So, I am doing a check when a user inputs an email to see if the email exists or not.

 $('form.recover-form#check-form').on('submit', function(e){

    var form    = $(this),
        input   = $('.check-recover-email'),
        span    = $('.recover-error'),
        email   = input.val();
    span.text('');
    e.preventDefault();
    $.ajax({
        url: 'ajax/check-email',
        async: 'false',
        cache: 'false',
        type: 'POST',
        data: {email: email},
        success: function(response) {
            if ( response == 'no' ) {
                span.text('email does not exist');
            } else if ( response == 'ok' ) {
                form.submit();
            }
        }
    });
});

The php code

if ( Input::isPost('email') )  {

    $email = Input::post('email');

    $check = $dbh->prepare(" SELECT * FROM users WHERE email = :email ");
    $check->execute(array( 'email' => $email ));

    echo ( $check->rowCount() == 1 ) ? 'ok' : 'no' ;

}

This way as soon as I submit the form it submits and the e.PreventDefault() inside the AJAX call is not working. If I put e.PreventDefault() before the AJAX call however, the form does not submit and the error appears if the email does not exists ( this is what I want to achieve ).

I can't understand where the problem is, hope you can help.

Thank you.

EIDT: This is the updated code

C. Ovidiu
  • 1,104
  • 2
  • 18
  • 38
  • you can't do that because of the asynchronous nature of ajax requests... – Arun P Johny Mar 31 '14 at 14:06
  • Just keep it outside the request as your were doing.. – tymeJV Mar 31 '14 at 14:07
  • e.preventDefault(); don't work because ajax is asynch call. Please make ajax synch or use callback to achive this – Sohil Desai Mar 31 '14 at 14:07
  • The flow of things is a bit confusing here. What is actually happening is that they user submits the form which triggers an ajax request which runs in the background. When that request returns you try to cancel the submit event but it is far to late, it has long ago completed. – George Mauer Mar 31 '14 at 14:09
  • 1
    Yes I understand the preventDefault() won't work inside the ajax call, but if I move it up before the ajax, how can I then resume the submit and go on submitting the form if the ajax call is successful ? – C. Ovidiu Mar 31 '14 at 14:17

6 Answers6

14

The problem is that you don't call preventDefault during the handling of the event. Instead, during the handling of the event, you start an ajax call (which is asynchronous), and then let the event continue. The ajax call completes later, which is too late to prevent the event's default — it's already happened.

Move the e.preventDefault() directly into the event handler, outside the ajax success handler.

$('.recover-form').on('submit', function(e){
    var form    = $(this),
        input   = $('.check-recover-email'),
        span    = $('.recover-error'),
        email   = input.val();
    span.text('');
    e.preventDefault(); // <=================== Here
    $.ajax({
        url: 'ajax/check-email',
        async: 'false',
        cache: 'false',
        type: 'POST',
        data: form.serialize(),
        success: function(response){
            if ( response == 0 ) {
                // ============================ Not here, this would be too late
                span.text('email does not exist');
            }
        }
    });
});

In a comment, you've said:

Yes, it works for the validation, but I want to submit the form if ajax returns a positive response. I only do a check with AJAX, if it fails stop the submit, if it succeed continue the submit.

You can't hold up the original form submission waiting for the result of an asynchronous ajax call. What you do instead is cancel the original form submission, do the ajax, and then if the result is okay, re-submit the form using the submit method on the raw DOM form element. That method doesn't re-trigger submit event handlers.

Example: Live copy

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<meta charset=utf-8 />
<title>Delaying form submit during ajax</title>
</head>
<body>
  <form action="http://www.google.com/search" method="GET">
    <input type="text" name="q" value="kittens">
    <input type="submit" value="Submit">
  </form>
  <script>
    (function() {
      $("form").submit(function(e) {
        var rawFormElement = this; // Remember the DOM element for the form

        // Stop form submission
        display("Got form submit event, simulating ajax");
        e.preventDefault();

        // Simulate ajax check of data
        setTimeout(function() {
          // (This is the 'success' callback for the ajax)
          display("Ajax call complete, pretending result is good and submitting");

          // All okay, go ahead and submit the form
          rawFormElement.submit(); // Doesn't trigger 'submit' handler
        }, 1500);
      });

      function display(msg) {
        $("<p>").html(String(msg)).appendTo(document.body);
      }
    })();
  </script>
</body>
</html>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Yes, it works for the validation, but I want to submit the form if ajax returns a positive response. I only do a check with AJAX, if it fails stop the submit, if it succeed continue the submit. – C. Ovidiu Mar 31 '14 at 14:36
  • @C.Ovidiu: To do that using an asynchronous ajax request, you'll have to stop the form submission, do the check, and if the check is okay submit the form programmatically instead. (The `submit` function on the raw DOM element for the form submits it without triggering `submit` handlers.) But as you're serializing the form anyway when doing the check, why not just handle it right there when processing the ajax call? – T.J. Crowder Mar 31 '14 at 14:42
  • In the end I just did that, basically need to send a recover email and I wanted to first check if the email exists in the database. Programmatically submitting didn't work for me, if you check @Arun answer he suggested it already. – C. Ovidiu Mar 31 '14 at 14:46
  • @C.Ovidiu: :-) In the meantime, I've added an example. *"Programmatically submitting didn't work for me"* Why not? – T.J. Crowder Mar 31 '14 at 14:50
  • Can't tell you the reason why because I don't know. The checks of the ajax response work and the error message appears or not accordingly, but the form does not submit. I did all in the ajax call in the end – C. Ovidiu Mar 31 '14 at 15:01
  • @C.Ovidiu: The only reasons I can think of for the form submission not working are: 1. All due respect, you had an error in your code submitting it, or 2. It had a `target` on it that would cause a new window/tab to be opened, and since it wasn't happening during the handling of a user-initiated event, the browser was preventing the popup. If you don't have a `target`, then the `submit` will work reliably. – T.J. Crowder Mar 31 '14 at 15:16
  • Don't worry, I am still a beginner so my code is not always correct, but in this case I triple-checked everything. For now I will leave it as it is and doing everything in the ajax call, but I will investigate further as soon as I have some time. Your answer however is perfect. – C. Ovidiu Mar 31 '14 at 15:19
4

You can't prevent the default action from a success handler of ajax request because of the asynchronous nature of it.

Instead by default prevent the form submission, then in the success handler if it is valid then call the submit again.

$('.recover-form').on('submit', function (e) {
    var form = $(this),
        input = $('.check-recover-email'),
        span = $('.recover-error'),
        email = input.val();
    span.text('');
    //prevent the submit
    e.preventDefault();
    $.ajax({
        url: 'ajax/check-email',
        async: 'false',
        cache: 'false',
        type: 'POST',
        data: form.serialize(),
        success: function (response) {
            if (response == 0) {
                span.text('email does not exist');
            } else {
                //submit if valie
                form[0].submit()
            }
        }
    });
});
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • I tried this but now I always get the error message as if the email I entered is always wrong ( which it isn't ). Just one question, submitting the form in the else block doesn't mean that it will always encounter the e.preventDefault() thus never submitting ? – C. Ovidiu Mar 31 '14 at 14:12
  • @C.Ovidiu no, submitting this way doesn't trigger the event handler. – Karl-André Gagnon Mar 31 '14 at 14:16
  • @Karl-AndréGagnon It does not work either. Now, I always get the error message, meaning that the if ( response == 0 ) if always true. The server side code is good and the email I am checking exists. – C. Ovidiu Mar 31 '14 at 14:24
  • 1
    @C.Ovidiu check the value of `response` – Arun P Johny Mar 31 '14 at 14:26
  • @ArunPJohny I am 75% there. I checked everything and if the email exists the error is removed, but the form stays still, does not submit. I'll post my code updated in the OP – C. Ovidiu Mar 31 '14 at 14:33
3

First, you're options are incorrect. cache and async require boolean values, not strings.

async: false,
cache: false,

Secondly, instead of submitting the form after the ajax request you're instead triggering the event. Try this instead.

form.get(0).submit();

It returns the form node rather than a jquery object, allowing you to submit it directly rather than triggering an event (otherwise you would have an infinite loop.)

You don't really need async: false or cache: false in this case.

Kevin B
  • 94,570
  • 16
  • 163
  • 180
1

You need to do the following:

$('.recover-form').on('submit', function(e){

    e.preventDefault();

    var form    = $(this),
        input   = $('.check-recover-email'),
        span    = $('.recover-error'),
        email   = input.val();
    span.text('');
    $.ajax({
        url: 'ajax/check-email',
        async: 'false',
        cache: 'false',
        type: 'POST',
        data: form.serialize(),
        success: function(response){
            if ( response == 0 ) {
                span.text('email does not exist');
            }
        }
    });
});

Notice how I've moved the e.preventDefault() to the beginning. This is because you were calling it when the ajax request responds which might happen 100s of milliseconds or even seconds after the form has been submitted

Petar Vasilev
  • 4,281
  • 5
  • 40
  • 74
  • This way it works and does not submit, but I want to submit the form if the email exists, if ( response == 1 ). – C. Ovidiu Mar 31 '14 at 14:26
0

This happens because success function passed for jQuery.ajax() is executed assyncly, then it will be executed after event handler function is finish.

You should put the e.preventDefault() out of ajax function. and everything will work.

Elias Soares
  • 9,884
  • 4
  • 29
  • 59
  • Yes, it works for the validation, but I want to submit the form if the ajax response returns a positive response. I only do a check with AJAX, if it fails stop the submit, if it succeed continue the submit. – C. Ovidiu Mar 31 '14 at 14:14
0

Better you can try something like this ,

<form name="myForm" onsubmit="return submitObj.validateAndSubmit();"> <!-- your form -->

<!-- your AJAX -->

var submitObj = {
  validateAndSubmit : function()
  {
    var form    = $('.recover-form'),
        input   = $('.check-recover-email'),
        span    = $('.recover-error'),
        email   = input.val();
    span.text('');
    $.ajax({
        url: 'ajax/check-email',
        async: 'false',
        cache: 'false',
        type: 'POST',
        data: form.serialize(),
        success: function(response){
            if ( response == 0 ) {
               return false;
            }
            else{
                return true;
            }
        }
    });     

  }

};
Dimag Kharab
  • 4,439
  • 1
  • 24
  • 45