Odd variable value capture timing

I have the following jQuery code that our back end guy came up with and he has asked me for help on it. The issue is that the value for the closeMsg variable is supposed to be set on either the success or the failure of the Ajax post but it bizarrely is not set unless a subsequent alert is set to display it. Then that alert doesn’t display but everything after that first alert does. Here is the code and I’m adding in comments around the alert to explain it a little better.

$('#confirmDeleteDelete').click(function (e) {
    var deleteUrl = baseUrl + 'delete/' + $('#confirmDeleteDelete').attr('name');
    var closeMsg = null;
    var closeUrl = null;

    //alert(deleteUrl);
    $.ajax({
        url: deleteUrl,
        type: 'POST',
        //data: {},
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            closeMsg = 'Successfully deleted record';
            closeUrl = baseUrl;
        },
        error: function (xhr, status, error) {
            closeMsg = 'Could not delete record, please try again';
            closeUrl = null;
        }
    });

    $('#promptDeleteMsg').hide();
    $('#confirmDeleteDelete').hide();
    $('#confirmDeleteCancel').hide();

    alert(closeMsg); // Here's the first alert; when it displays it shows a value of "null"
    alert(closeMsg); // Here's the second alert; when it displays it shows a value of "Successfully deleted record" (assuming a successful Ajax post)
    $('#promptDeleteMsg').after('<p id="#confirmDeleteMsg" />').text(closeMsg).show(); // This is where we actually want the value to show up but it doesn't unless at least the first alert is in place
    $('#confirmDeleteClose').attr('name', closeUrl);

    $('#confirmDeleteClose').show();
    e.preventDefault();
});

Any ideas? If it helps anything there doesn’t seem to be any problem capturing the associated closeUrl variable value.

This would be completely expected behaviour. The code above is pretty sound and it doesn’t actually need too much more to make it work :slight_smile:

The reason it fails is because the code is asynchronously connecting to the server and retrieving data, this also means that it is not blocking the other code from running. So what happens in a normal scenario is this:

  • User clicks button
  • Button event handler kicks in
  • AJAX request fires
  • Code after the AJAX request call runs
  • AJAX request finishes, success and error callbacks are called if necessary

However, in your scenario the alert() calls block the code from continuing, but the AJAX request finishes, the second alert now has a value for closeMsg.

To fix this code, we can simply add another callback in to your AJAX call for “complete” … as per the jQuery.ajax() documentation, ‘complete’ fires after success and/or error have been called.


$('#confirmDeleteDelete').click(function (e) {

    //declare all variables at the top, this can be done with one 'var' statement :)
    var deleteUrl = baseUrl + 'delete/' + $('#confirmDeleteDelete').attr('name'),
        closeMsg = null,
        closeUrl = null;

    //prevent default event handler from occurring as early as possible
    e.preventDefault();

    //we can combine all these in to a single selector
    $('#promptDeleteMsg, #confirmDeleteDelete, #confirmDeleteCancel').hide();

    $.ajax({
        url: deleteUrl,
        type: 'POST',
        //data: {},
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            closeMsg = 'Successfully deleted record';
            closeUrl = baseUrl;
        },
        error: function (xhr, status, error) {
            closeMsg = 'Could not delete record, please try again';
            closeUrl = null;
        },
        //the complete callback will fire after the success / error callbacks
        complete: function(xhr, status) {
            $('#promptDeleteMsg').after('<p id="#confirmDeleteMsg" />').text(closeMsg).show();
            $('#confirmDeleteClose').attr('name', closeUrl).show(); //it's fine to chain .show() on here as well.
        }
    });

});

Thanks, AussieJohn. Going to implement now.

Okay, that one worked. Now I’m trying to get a similar one to work.

if (isTagDefined(ajaxgetleftnav)) {
    if (isTagDefined(getdataids))
        ajaxgetleftnav = ajaxgetleftnav + getdataids;

    $.ajax({
        url: ajaxgetleftnav,
        type: 'GET',
        //data: {},
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            if (isTagDefined(leftnav_datadiv)) {
                $(leftnav_datadiv).html(data);
                $(leftnav_datadiv).dataTable();
            }
            //$('.leftnav_status').html('success getting data');
            //$('.leftnav_status').removeClass('content_error').addClass('content_success');
            if (isTagDefined(leftnav_navdiv) && isTagDefined(leftnavCTApath)) {
                $(leftnav_navdiv).load(leftnavCTApath);
                alert('hi planet'); // need to find a way for the next line to work without this alert being in place;
                $('#createitem IMG').after('&nbsp;New&nbsp;' + entityName);
            }
        },
        error: function (xhr, status, error) {
            console.log('fail');
            $('.leftnav_status').html('error getting data');
            $('.leftnav_status').removeClass('content_success').addClass('content_error');
        }
    });
}

I suppose it’s a matter of where to put the e.preventDefault statement and maybe where to put a complete statement too, but this example is different because I want to do something within a success statement rather than after the success/error part, but none of my tinkering has been successful yet.


if (isTagDefined(leftnav_navdiv) && isTagDefined(leftnavCTApath)) {
    $(leftnav_navdiv).load(leftnavCTApath);
    alert('hi planet'); // need to find a way for the next line to work without this alert being in place;
    $('#createitem IMG').after('&nbsp;New&nbsp;' + entityName);
}

I’m not sure where that would be falling over, is entityName already defined (and does “#createitem img” already exist?).

Yes to “#createitem img” already existing (yeah, I’m weird, I put HTML elements within JavaScript statements in uppercase to increase readability for myself). Let me check on the entityName issue…

UPDATE: It’s looking like it could be an issue of when entityName is defined. I’m not getting a clear answer on that right now and might have to wait until our back end guy comes back from his days off.