0

In my angularJS app, I have a loop that increments x times. I'm using a nested HTTP get request within the loop to get an API response for each iteration.

The problem is that the loop counter within the HTTP get function is not getting the correct incrementation value.

// split multiple words
var split = ['stack', 'over'];

// for each word
for(var w = 0; w < split.length; w++) {

    // API URL
    var api_url = "URL" + split[w]; // correct iteration value, 0, 1, 2, etc...

    // get data from API
    $http.get(api_url)

        // handle successful
        .success(function (response) {

            console.log(w); // logs 2 everytime! Instead of 0, 1, 2, etc...
    });
} 

Any ideas on how to solve this?

Kyle
  • 1,153
  • 5
  • 28
  • 56

3 Answers3

1

Your $http.get() is asynchronous. Your for loop does NOT wait for the asynchronous calls to finish. Thus, your for loop runs to completion, starts all the ajax calls, then sometime later your $http.get() calls finish and trigger the .success handler. Thus, the loop index is on its ending value when each of the $http.get() calls are done. And, the ending value for your loop index is 2.

You can fix it by putting your $http.get() into a function and passing the loop index into that function. This internal function (often called an Immediately Invoked Function Express IIFE) keeps track of the loop index separately for each invocation of your ajax call so each has its own index:

// split multiple words
var split = ['stack', 'over'];
// for each word
for (var w = 0; w < split.length; w++) {
    (function (i) {
        // API URL
        var api_url = "URL" + split[i];
        // get data from API
        $http.get(api_url)
            // handle successful
            .success(function (response) {
                console.log(i); // logs the index that belongs with this ajax call
            });
    })(w);
}

P.S. It is not clear to me what word_index is since you don't define that? Is that supposed to be the loop index?

Note that w is the variable used in the for loop. That is passed into the newly added internal function as an argument which I have purposely given a different name as i. So, w is passed into the function and the function argument names that variable i.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • @Esko - No. You aren't understanding how the internal function works. I also rejected your edit because it was wrong. Please read the last paragraph I added to my answer. The `for` loop variable `w` is passed in as an argument to the internal function see the `(w)` near the end of the code block. That becomes the function argument `i` within the function. I purposely made `i` and `w` different. – jfriend00 Nov 04 '15 at 00:49
  • Thank you for verifying the "w". I see it now :) An iffy closure – Esko Nov 04 '15 at 00:50
0

split[word_index] should be changed to split[w]

Esko
  • 683
  • 9
  • 23
0

You are logging the value of w in the success handler, i.e. when the client received a server response.

The response is sent over the network and is therefore received asynchronously.

At the time the first response is handled, all the requests are already sent.

If you need the word value in the http response handler, then consider refactoring your API: maybe it make sense to have the word as a request parameter (not as a part of the string url), or to have it in the response object. You could then get the value without hacky captures.

Also, consider using then instead of success:

$http.get(api_url).then(function(httpResponse) {
    // request parameters are in httpResponse.config.params
});
Michel
  • 26,600
  • 6
  • 64
  • 69