1

I have a function that looks like this:

function showCreditCard(idx, data) {

    if(typeof cardInfo == 'undefined' && parseInt($("#cc-dropdown-" + idx + " option:selected").val(),10) > -1) {
       // actual selection made, but not default, so cardInfo hasn't been set. Need to run ajax call to get credit card;
       console.log("show dropdown");
       console.log("there are saved cards and a selection was made");
       poGetPaymentOption('credit card', parseInt($("#cc-dropdown-" + idx + " option:selected").val(),10), idx);

        // this is the default card; display dropdown with default selected and static fields
        console.log("supposedly after poGetPayment");
        console.dir(cardInfo);

        // why is this stuff running before poGetPaymentOtion finishes and returns a cardInfo object?
        if( cardInfo.cc.cc_type == 'VI' ) { $('#cc_visaBig-'+idx).attr('class', 'cc_visaBig'); }

        $('#cc-static-wrap-'+idx).show();
        updateButtonState();

    }

}

As you can see by the comments, the lines after the poGetPaymentOption call are running before that function is actually complete. I've verified this with logs in the poGetPaymentOption function as well (below).

function poGetPaymentOption(type, key, bIdx) {
   if( type == 'credit card' ) {
      console.log("signed in, credit card");
      $.post('/site/ajax/customers/getSingleCreditCard',
          { 'key': key },
          function(data) {
            if( data.success == 1 ) {
                console.log("poPayment success");
                    if(typeof cardInfo == 'undefined') {
                        cardInfo = new saveCardInfo(data);
                    }    

            } else {
              console.log("poPayment no success");
            }
          }, 'json');
    } 
}

What I would expect to happen is for the call from showCreditCard to poGetPaymentOption to return success via the ajax call (which it does) and then create a new saveCardInfo object called cardInfo. It does happen, as far as I can tell, but the lines checking cardInfo.cc.cc_type and beyond are all happening before the object is created. I've attached a screenshot of my Firebug console so it's apparent the order things are happening.

enter image description here

What am I doing wrong? I need to make sure that poGetPaymentOption is fully complete and cardInfo has been created before continuing further in the showCreditCard function.

EmmyS
  • 11,892
  • 48
  • 101
  • 156
  • 1
    Use $.ajax instead of $.post and set async to false. – XCS Mar 20 '13 at 22:52
  • You need to execute the rest of your 1st method when poGetPaymentOption() is over. You need a callBack function. – Hanlet Escaño Mar 20 '13 at 22:54
  • 3
    @Cristy: No. While possible, it's not advisable. – Bergi Mar 20 '13 at 22:54
  • @Cristy: Sure that would fix the symptom, but not the problem. `async: false` would stop all further JS execution while the AJAX call is connecting to the server. On a slow connection, that is horrible. – Steve Mar 20 '13 at 22:58
  • @Bergi - which part is not advisable? Using $.ajax or setting async to false? – EmmyS Mar 21 '13 at 01:13
  • @Steve, I know, this is an option, not the solution, that's why it's only a comment. :) The solution would be to make the next function call in the `success` function of the AJAX request, so it will be called only when the AJAX is completed. – XCS Mar 21 '13 at 09:24

2 Answers2

1

The AJAX call is asynchronous, so the success callback function will be called when the response has arrived, not immediately.

Actually, while your code is running the event that happens when the response arrives can't be handled. Even if the response arrives before you exit the showCreditCard function, the event won't be handled until you have exited the function, so the callback will never be called until after you have exited the showCreditCard function.

To make use of the data that is fethed, you need to do that in the success callback function. Either move the code into that function, or send a callback function into the poGetPaymentOption, so it can call it when the response has arrived.

(For completeness; making a synchronous call instead would make your code work without rearranging it, but it's not advisable as it freezes the browser while it's waiting for the response.)

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • I'm not sure I understand which code I'm supposed to move into a success callback. All of the code in `showCreditCard`? That won't work. What I've shown here is a stripped-down version of that function; it's actually called in multiple places, and there are a variety of conditions inside it - not all of them rely on `poGetPayment`, so I can't move all of that code into it without also needing to duplicate it somewhere else so it can be called in other situations. – EmmyS Mar 21 '13 at 01:37
  • @EmmyS: You only need to move the code that rely on the result from the AJAX call. You can put that code in a callback function in `showCreditCard` which will let you keep the code in the same place, but from the point of view of the program flow, the code is in a separate function. – Guffa Mar 21 '13 at 08:38
0

This happens because $.post() executes asynchronously.

Basically, your JS code continues synchronously while the AJAX call is going to the server. Only when the server responds your callback function gets executed.

In your exact example, everything after poGetPaymentOption('credit card', parseInt($("#cc-dropdown-" + idx + " option:selected").val(),10), idx); will execute way before your anonymous function gets executed:

      function(data) {
        if( data.success == 1 ) {
            console.log("poPayment success");
                if(typeof cardInfo == 'undefined') {
                    cardInfo = new saveCardInfo(data);
                }    

        } else {
          console.log("poPayment no success");
        }
      }

To fix this, you would need to move the rest of you showCreditCard function within the callback. Or alternatively create another function that gets called within the callback.

Steve
  • 8,609
  • 6
  • 40
  • 54