0

I'm looking for a way to modify a variable declared outside of a callback, then use the modified variable after defining the callback. My intent is reflected in the code:

$('#my_form').submit(function() {
    let my_condition
    let data = $(this).serialize()
    $.ajax({
        method: 'POST',
        url: '/my_url',
        data: data
    })
    .done(function(json_response) {
        if (json_response.my_variable) {
            my_condition = true
        }
        else {
            my_condition = false
        }
    })
    // I'm looking for a way to guarantee `my_condition` is set by the AJAX before the below code is run.
    if (my_condition) {  // I know `my_condition` will be null because this line won't wait for the AJAX to finish and set `my_condition`.
        return true
    }
    else {  // The event handler will always hit this condition.
        return false
    }
})

I'm aware that I could add blocking sleep time before checking my_condition to wait for the AJAX. This is not a solution I'm looking for. I'm also aware that I could set my_condition based on inspecting data on the frontend. However, for reasons specific to my use case, data needs to be processed on the backend. Lastly, I want to avoid the AJAX setting async: false.

I know why the code above does not work. My question is, is there some way to achieve the desired result? I have a feeling there might be a solution that uses Promise, but I don't see exactly how that would be done.

Edit 1: The specific use case is with regards to form submission. I want the submit handler to return true or false, i.e., submit via the form's action attribute (when my_condition is true) or a different (AJAX) route (when my_condition is false) based on backend processing results of data.

Edit 2: This is indeed a duplicate of Javascript - Stop form submit depending on ajax response [duplicate]

Andrew
  • 55
  • 6
  • You can't program this way. The ajax call is non-blocking and asynchronous. That means your `if (my_condition)` executes BEFORE the `.done()` calls the callback so you're trying to use the `my_condition` value BEFORE it has been set. – jfriend00 May 04 '21 at 19:59
  • Thanks. Yes, as I mentioned, I know why the code does not work. My question was whether there is a different pattern, perhaps using Promise, that is capable of achieving the same effect. – Andrew May 04 '21 at 20:16
  • @Andrew This is not possible (without using synchronous XHR). Instead, always prevent the default action of the submit event, and then when the server response is affirmative do `.submit()` the form. – Bergi May 04 '21 at 20:45
  • @Bergi Thanks, I did not know about preventDefault. – Andrew May 04 '21 at 20:51
  • @Andrew That's basically what `return false` in a jQuery event handler does – Bergi May 04 '21 at 20:51
  • Well, you never really explained what the desired effect/purpose is with this code. Your `$.ajax()` call is ALREADY submitting the form so why would you want to submit it again? The usual work-around with asynchronous code is to always block the browser submit and just do any other submits entirely via Javascript. Then, you fully control it. – jfriend00 May 04 '21 at 20:54
  • @Bergi Thanks, the key was storing the form in the variable before `$.ajax`. – Andrew May 04 '21 at 21:17

1 Answers1

2

I suspect (although specific problem is not clear) you want the form to submit only if you get a valid response in the ajax.

You can prevent the initial submit and then submit the form inside the done callback if condition is met.

$('#my_form').submit(function(e) {
    // prevent submit
    e.preventDefault()
    let form = this;
    let data = $(form).serialize()
    $.ajax({
        method: 'POST',
        url: '/my_url',
        data: data
    })
    .done(function(json_response) {
        if (json_response.my_variable) {
           // trigger native submit, will bypass this jQuery submit listener
           form.submit()
        }
        else {
            // do something else
        }
    })
 })  
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • This doesn't really make sense because the `$.ajax()` call is already submitting the form so why submit it again. It is unclear what the purpose/intention of the OP's code was. – jfriend00 May 04 '21 at 20:52
  • I think it does make sense. The original code actually never submitted the form because the submit handler callback (expectedly) always returned false. The AJAX call is not necessarily submitting the form. The form's `action` attribute could have a completely different value than `/my_url`. This solution allows for a way to submit the form in different ways based on results from server processing of the submission data. Sorry if the question was unclear. – Andrew May 04 '21 at 21:23