2013-05-07 15 views
20

Jak dodać funkcję zwrotną po asynchronizacji dla pętli "Czytaj pętlę"?wywołanie zwrotne po asynchronizacji dlaAnie AngularJS

Oto lepszy kontekst:

$scope.getAlbums = function(user, callback) { 
    $scope.albumsList.forEach(function (obj, i) { 
     $scope.getAlbum(user, obj.id, function(value){ 
      $scope.albums.push(value); 
     }); 
    }); 
    // callback(); ??? 
}; 

$scope.getAlbums('guy123', function(){ 
    // forEach loop is all done! 
    console.log($scope.albums) 
}); 

Kontroler:

.controller('Filters', ['$scope','Imgur', function($scope, Imgur) { 

    $scope.getAlbum = function(user, id, callback) { 
     Imgur.album.get({user:user, id:id},  
      function(value) { 
       return callback(value.data); 
      } 
     ); 
    } 

    $scope.getAlbums = function(user, callback) { 
     // Callback function at end of this forEach loop? 
     // Request is async... 
     $scope.albumsList.forEach(function (obj, i) { 
      $scope.getAlbum(user, obj.id, function(value){ 
       $scope.albums.push(value); 
      }); 
     }); 
    }; 
)]}; 

Usługa:

.factory('Imgur', function($resource) { 
    return { 
     album : $resource('https://api.imgur.com/3/account/:user/album/:id') 
    } 
}); 

Odpowiedz

44

Zgodnie z opinią Andrew użycie $q i odroczonego obiektu powinno pozwolić na osiągnięcie celu.

Chcesz użyć $q.all() Pozwoli to upewnić się wszystkich przedmiotów obietnica zostały rozwiązane, a następnie możesz zadzwonić do połączenia z powrotem w .then()

function MyCtrl($scope, $q, $http) { 

    $scope.albumsList = [{ 
      id: 1, 
      name: "11" 
     }, { 
      id: 2, 
      name: "22" 
     } 
    ]; 
    $scope.albums = []; 
    $scope.getAlbum = function(user, id, callback) { 
     return $http.get("https://api.imgur.com/3/account/" + user + "/album/" + id).success(
      function(value) { 
       return callback(value.data); 
      } 
     ); 
    } 
    $scope.getAlbums = function (user, callback) { 
     var prom = []; 
     $scope.albumsList.forEach(function (obj, i) { 
      prom.push($scope.getAlbum(user, obj.id, function(value){ 
       $scope.albums.push(value); 
      })); 
     }); 
     $q.all(prom).then(function() { 
      callback(); 
     }); 
    }; 
    $scope.getAlbums('guy123', function() { 
     alert($scope.albums.length); 
    }); 
} 

Example with this on jsfiddle

działa, ale nie z $http połączeń

W przypadku obiektu odroczonego uzyskujesz dostęp do obietnicy, w której możesz zmienić kolejnePołączenia. Po rozstrzygnięciu odroczonego obiektu wykona on foreach, a następnie uruchomi funkcję zwrotną, którą dostarczyłeś. Próbowałem nieco uprościć twój przykład, aby działał w jsfiddle.

function MyCtrl($scope, $http, $q) { 

    $scope.albumsList = [{ 
     id: 1, 
     name: "11" 
    }, { 
     id: 2, 
     name: "22" 
    }]; 
    $scope.albums = []; 
    $scope.getAlbums = function (user, callback) { 
     var deferred = $q.defer(); 
     var promise = deferred.promise; 
     promise.then(function() { 
      $scope.albumsList.forEach(function (obj, i) { 
       $scope.albums.push(obj); 
      }); 
     }).then(function() { 
      callback(); 
     }); 
     deferred.resolve(); 
    }; 
    $scope.getAlbums('guy123', function() { 
     alert($scope.albums.length); 
    }); 
} 

Example on jsfiddle

A bit more reading on deferred and promises.

+0

To jest dokładnie to, czego potrzebowałem, jednak kiedy próbuję z zewnętrznymi danymi zasobowymi --- nie zawiera to obietnicy;) ... Czy mógłbyś podać przykład z dowolnymi danymi API, takimi jak twitter? –

+0

Ponieważ używasz '$ resource', który również zwraca obietnicę, będziesz musiał zmodyfikować swój kod, aby połączyć obietnice razem i wywołanie' resolve() 'uruchamia cały mechanizm. –

+0

Zobacz aktualizację przykładu na jsfiddle, która symuluje posta ajaxowego. –

0

I t wygląda na odroczoną http://docs.angularjs.org/api/ng.$q, a konkretne przyrzeczenia mogą być tu przydatne.

+0

Czy możesz podać przykład w kontekście tego problemu :)? –

+0

Proszę zobaczyć odpowiedź Marka powyżej. –

5
$scope.getAlbums = function(user, callback) { 

     var promiseArr = []; 
     $scope.albumsList.forEach(function (obj, i) { 
      var anHttpPromise = 
      $scope.getAlbum(user, obj.id, function(value){ 
       $scope.albums.push(value); 
      }); 
      promiseArr.push(anHttpPromise); 
     }); 

     $q.all(promiseArr).then(function(){ 
      // This callback function will be called when all the promises are resolved. (when all the albums are retrived)  
     }) 
    }; 

    $scope.getAlbum = function(user, id, callback) { 
     var anHttpPromise = Imgur.album.get({user:user, id:id},  
      function(value) { 
       return callback(value.data); 
      } 
     ); 
     return anHttpPromise; 
    } 

W powyższym kodu:

  1. getAlbum się do zwracania obiecujące.
  2. Zbieranie się obiecujące dla każdej iteracji listy
  3. getAlbums Gdy wszystkie obietnice są zbierane, tablica obietnica jest przekazywana do $q.all
  4. Sposób $q.all zamiast zwraca się ostatecznej obietnicy którego zwrotna funkcja zostanie uruchomiona po raz wszystkie obietnice w tablicy są rozwiązane.
+0

Wprowadziłem w życie Twoje rozwiązanie i wprowadziłem ostatnie zmiany do projektu @ https://github.com/gigablox/angular-imgur-gallery/blob/master/app/js/controllers.js. Jednak wciąż nie odraczam obietnicy. Mabye, coś mi umknęło? –

4

Używanie $resource obietnicę PR commit trafi do 1.1.3, byłem w stanie owinąć $resource połączenia z $ q i kontrolować przepływ ich asynchronicznym behavoir.

$scope.getAlbum = function(user, id, callback) { 
    var promise = Imgur.album.get({user:user, id:id}).$promise.then(
     function(value){ 
      return callback(value.data); 
     }, 
     function(error){ 
      //Something went wrong! 
     } 
    ) 
    return promise; 
} 

$scope.getAlbums = function(user, callback) { 
    var prom = []; 
    $scope.albumsList.forEach(function (obj, i) { 
     var promise = 
     $scope.getAlbum(user, obj.id, function(value){ 
      $scope.albums.push(value); 
     }); 
     prom.push(promise); 

    }); 

    $q.all(prom).then(function() { 
     callback(); 
    }); 
}; 

$scope.getAlbums(user, function(){ 
    // Totally works, bro. 
    console.log($scope.albums); 
}); 
Powiązane problemy