Craig Roberts
Craig Roberts

Reputation: 171

How to get a for loop to wait for each callback to finish

I am calling a service to get an array of IDs then looping through each of them and calling another service to their respective data. The console is showing that the getBookings service in a for loop is not processing in sequence.

   service.getStoreIDs(function (data1) {
        var scheduledBookings = [];

        console.log('StoreIDs = ' + data1.length); // There are only 3 in my test data

        for (var storeID in data1) {
            var s = data1[storeID];
            var storeno = s['Storeno'];

            service.getBookings(storeno, "", function (data2) {

                if (data2.length == 0) {
                    scheduledBookings.push({ Storeno: storeno, Id: 0 });
                }
                else {
                    console.log('[BuildMFB] Storeno ' + storeno + ' = ' + data2.length + ' bookings')
                    for (var book in data2) {
                        var b = data2[book];

                        prevStoreno = storeno;

                        scheduledBookings.push({
                            Storeno: (prevStoreno == storeno ? "" : storeno),
                            Id: b.Id,
                            BookedBy: b.BookedBy,
                            Description: b.Description,
                            StartDate: b.StartDate,
                            EndDate: b.EndDate,
                        });
                    }
                    prevStoreno = storeno;
                }
            });
        }
        $scope.currentBookings = scheduledBookings;
    });

All the bookings are being assigned to the store 144 as you can see from the console messages below which is not right as it only has 1 booking.

I can only think that this is an async processing issue (?).

Console message (BuildMFB is current function):

[BuildMFB] StoreIDs = 3
[BuildMFB] storeID: 101
[BuildMFB] storeID: 131
[BuildMFB] storeID: 144
[getBookings] Storeno 101 has 5 bookings
[BuildMFB] Storeno 144 = 5 bookings
[BuildMFB] Added 253 for 144
[BuildMFB] Added 151 for 144
[BuildMFB] Added 215 for 144
[BuildMFB] Added 217 for 144
[BuildMFB] Added 208 for 144
[BuildMBF] currentBookings = 5
[getBookings] Storeno 131 has 2 bookings
[BuildMFB] Storeno 144 = 2 bookings
[BuildMFB] Added 227 for 144
[BuildMFB] Added 226 for 144
[BuildMBF] currentBookings = 7
[getBookings] Storeno 144 has 1 bookings
[BuildMFB] Storeno 144 = 1 bookings
[BuildMFB] Added 238 for 144
[BuildMBF] currentBookings = 8

Updated with getBookings method:

var getBookings = function (storeno, userid, callback) {
    var filterString = "";

    if (storeno != "0" && userid != "") {
        filterString = "?$filter=(Title eq '" + storeno + "') and (Status eq 'Booked') and (BookedBy eq '" + userid + "')&$orderby=Title asc";
    }
    else if (storeno != "0") {
        filterString = "?$filter=(Title eq '" + storeno + "') and (Status eq 'Booked')&$orderby=Title asc";
    }
    else if (userid != "") {
        filterString = "?$filter=(Status eq 'Booked') and (BookedBy eq '" + userid + "')&$orderby=Title asc";
    }
    else {
        filterString = "?$filter=(Status eq 'Booked')&$orderby=Title asc";
    }

    $http({
        method: 'GET',
        url: "/_api/web/lists/GetByTitle('Bookings')/Items" + filterString,
        headers: {
            'Accept': 'application/json; odata=verbose'
        },
    }).success(function (d) {
        var bookings = [];

        $(d.d.results).each(function (i, e) {
            bookings.push({
                Id: e['Id'],
                Storeno: e['Title'],
                BookedBy: e['BookedBy'],
                Description: e['Description'],
                StartDate: e['StartDate'],
                EndDate: e['EndDate'],
            });
        });

        callback(bookings);

    }).error(function (er) {
        alert("[getBookings] http error : " + er);
    });
};

Upvotes: 0

Views: 550

Answers (1)

pmccloghrylaing
pmccloghrylaing

Reputation: 1129

While you have defined local variables within your for loop their definition will actually be hoisted to the start of the function, those variables are then getting updated on each iteration before any of your asynchronous tasks have completed. A simple solution is to use a foreach utility function like jQuery's $.each or underscore's _.each which calls a function for each iteration.

EDIT: Sorry, updated for key values rather than an array.

...
$.each(data1, function (storeID, s) {
    var storeno = s['Storeno'];
    ...
});
...

Upvotes: 1

Related Questions