andrbmgi
andrbmgi

Reputation: 528

AngularJS asynchronous requests in a for loop

I display a list, each item includes an array of ids that reference other documents (mongodb). When the user clicks on an item I want to populate the array with the actual documents (= replacing the ids with the corresponding object).

My problem is that the data is not applied to the correct place in the array once the requests finish. Probably the index that I hand over in the callback function is increased as the for loop marches on. By the time the request is ready, the for loop likely already finished so the result gets attached to the end of the array instead of its original position. I tried deep copying the index with angular.copy() although I believe that should not be necessary. I am not even sure if int is an object or a flat datatype, a small Google research yielded no clear answer to that.

I was able to re-create the problem in a plunkr.

I encountered a similar problem before but was able to work around it but this time I am not sure how to deal with this problem. Any hints?

Upvotes: 0

Views: 382

Answers (2)

Anthony Chu
Anthony Chu

Reputation: 37520

You need to properly capture i for the current iteration by passing it into fetchSubItem()...

for( var i=0; i < item.subItems.length; i++ ) {
    // in the real world app fetchSubitem does an http api call
    fetchSubItem( item.subItems[i], i, function(result, i){
      // this happens long after the for loop and all finished
      item.subItems[i] = result;
    });
}

// ....

function fetchSubItem ( id, j, callback ) {
    var found = false
    for( var i=0; i < sideList.length; i++ ) {
      if ( sideList[i].id == id ) {
        found = true;
        $timeout( function(){ callback( sideList[i], j ); }, 1000 ); // to simulate asynchronicity
        break;
      }
    }
    if ( !found ) callback( "SubItem "+id+" not found.", j );
}

Plunker: http://plnkr.co/edit/8qTNUwjyWYrokc1bTXLI?p=preview

Upvotes: 1

Zack Argyle
Zack Argyle

Reputation: 8407

The asynchronous call will assume the value of 'i' at the time it is invoked. Because of that you need to write a helper function to save the value of i. Something like this should work.

function fetchSubItem ( id, callback ) {
    function helper(i) {
        $timeout( function(){ callback( sideList[i] ); }, 1000 ); // to simulate asynchronicity
    }

    var found = false

    for( var i=0; i < sideList.length; i++ ) {
        if ( sideList[i].id == id ) {
            found = true;
            helper(i);
            break;
        }
    }
    if ( !found ) callback( "SubItem "+id+" not found." );
}

Upvotes: 0

Related Questions