AngularJS - poczekaj na zakończenie wielu zapytań o zasoby

105

Mam jedną fabrykę zdefiniowaną w ngResource:

App.factory('Account', function($resource) {
    return $resource('url', {}, {
        query: { method: 'GET' }
    });
});

Wykonuję wiele wywołań metody zapytania zdefiniowanej w tej fabryce. Wywołania mogą być wykonywane asynchronicznie, ale przed kontynuowaniem muszę poczekać na zakończenie obu wywołań:

App.controller('AccountsCtrl', function ($scope, Account) {
    $scope.loadAccounts = function () {
        var billingAccounts = Account.query({ type: 'billing' });
        var shippingAccounts = Account.query({ type: 'shipping' });

        // wait for both calls to complete before returning
    };
});

Czy istnieje sposób, aby to zrobić z fabrykami AngularJS zdefiniowanymi za pomocą ngResource, podobnie do funkcji $ .when (). Then () z jQuery? Wolałbym nie dodawać jQuery do mojego obecnego projektu.

Nathan Donze
źródło

Odpowiedzi:

201

Będziesz chciał użyć obietnic i $ q.all () .

Zasadniczo można go użyć do zawijania wszystkich wywołań $ resource lub $ http, ponieważ zwracają one obietnice.

function doQuery(type) {
   var d = $q.defer();
   var result = Account.query({ type: type }, function() {
        d.resolve(result);
   });
   return d.promise;
}

$q.all([
   doQuery('billing'),
   doQuery('shipping')
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...
});
Ben Lesh
źródło
17
Zasoby nie zwracają obietnic, zwracają obiekty do wypełnienia w przyszłości. Jednak w niestabilnej wersji 1.1.3 zasoby również mają $thenwłaściwość, ale nie ujawniają żadnego obiektu obiecującego. $promiseCałkowite ujawnienie nastąpi w wersji 1.1.4
Umur Kontacı
@ UmurKontacı To niestety nie występuje w kątowej 1.1.4!
nh2
Szczegóły dotyczące problemu z zasobami nie są obietnicami można znaleźć w tym wątku oraz w tym żądaniu ściągnięcia .
nh2
1
Ta odpowiedź pokazuje, jak ją napisać po wdrożeniu.
nh2
3
Twoja odpowiedź jest bardzo pomocna i uważam, że jest to najrozsądniejszy sposób przekształcania zasobów w obietnice w obecnym ujęciu. Pomocne może być dodanie, że w dokumentacji $q, do której utworzono łącze, gwarantuje ona, że ​​tablica wynikowa jest w tej samej kolejności, co tablica obietnicy.
nh2
20

Myślę, że lepszym rozwiązaniem jest:

$q.all([
   Account.query({ type: 'billing' }).$promise,
   Account.query({ type: 'shipping' }).$promise
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...
});
Tales Mundim Andrade Porto
źródło
1
U mnie pracował bez obietnicy $ na końcu ... Tak jak: Account.query ({type: 'billing'}), Account.query ({type: 'shipping'})
georgeos
12

Rozwiązanie firmy Ben Lesh jest najlepsze, ale nie jest kompletne. Jeśli chcesz poradzić sobie z warunkami błędu - i tak, robisz - musisz użyć catchmetody w obiecującym interfejsie API w następujący sposób:

$q.all([
   doQuery('billing'),
   doQuery('shipping')
]).then(function(data) {
   var billingAccounts = data[0];
   var shippingAccounts = data[1];

   //TODO: something...

}).catch(function(data) {

   //TODO: handle the error conditions...

}).finally(function () {

  //TODO: do final clean up work, etc...

});

Jeśli nie zdefiniujesz, catcha wszystkie obietnice zawiodą, thenmetoda nigdy nie zostanie wykonana, a zatem prawdopodobnie pozostawi twój interfejs w złym stanie.

Nick A. Watts
źródło