0

I am stuck with a function that has to process an array, and as part of this it has to loop over it and perform an ajax call using a value to determine if it's valid. If errors are found it returns a string of error messages after it has processed all the data. How do I ensure the ajax calls all complete before the functions returns, bearing in mind that they will only fire on some loops?

I've tried all sorts of deferred / promise related things but can't get it right :( I don't believe this is as straightforward as "how do I get return async data" due to the forEach, or even if the principle is the same I'm struggling with the implimentation.

Trimmed code below - note the // Do other stuffs - both within the forEach in case that makes a difference. A watcher calls handleFileSelect(), which then calls basicValidation();

function basicValidation( data ) {
    // Store errors to be returned.
    var failed = '';
    // Loop over each row and validate.
    data.forEach( function( row, index ) {

        // Do other stuff.

        if ( a ) {
            // Do stuff.
        } else if (b) {
            // Do ajax bit that only happen sometimes.
            $.ajax({
                url: 'https://api.postcodes.io/postcodes/' + row[5],
                success: function (data) {
                    if ( 200 !== data.status ) {
                        failed += 'Row ' + index + ':: invalid Address - lookup failed.\n';
                    }
                    // Do other checks.
                },
                error: function (request, status, error) {
                    console.log(  'Postcode lookup request failed:: ' + request.responseText + '\n' + status + '\n' + error );
                }
            });
        }

        // Do other stuff.
    }

    return failed;
}


function handleFileSelect( results ) {
    // Do the basic front-end validation.
    var validation = basicValidation( results.data );
    if ( validation.length ) {
        alert( 'Failed.\n\n' + validation + '\nPlease correct your data, refresh the page, and try again.' );
        return false;
    }
}
phil
  • 174
  • 15
  • look into `$.when` – Jaromanda X Oct 10 '17 at 20:34
  • your big problem is that both the functions you've shown want to return a synchronous result (`failed` and `false`) - this can not happen once you've introduced asynchronous code - so, how `handleFileSelect` is called will also need to be changed – Jaromanda X Oct 10 '17 at 21:46
  • Thanks @JaromandaX - but I need a bit more handholding. I can do a basic async function using $.Deferred() and $.when, but I can't get it working in this specific context. – phil Oct 11 '17 at 08:49
  • In handleFileSelect I can do: `var validation = basicValidation( results.data ); $.when( validation ).done(function( results ) { if ( results.length ) { alert( 'Failed.\n\n' + results + '\nPlease correct your data, refresh the page, and try again.' ); return false; } });` Which works for a simple async function, but it's getting the basicValidation function function setup correctly I'm having problems with. – phil Oct 11 '17 at 08:55

1 Answers1

0

Have you tried setting async: false in your AJAX?

According to docs:

async (default: true) Type: Boolean By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false.

This will wait for the response before continuing.

// Do ajax bit.
        $.ajax({
            url: 'https://api.postcodes.io/postcodes/' + row[5],
            async: false,
            success: function (data) {
                if ( 200 !== data.status ) {
                    failed += 'Row ' + index + ':: invalid Address - lookup failed.\n';
                }
                // Do other checks.
            },
            error: function (request, status, error) {
                console.log(  'Postcode lookup request failed:: ' + request.responseText + '\n' + status + '\n' + error );
            }
        });
Jeramiah Harland
  • 854
  • 7
  • 15