AngularJS - attendez que plusieurs requêtes de ressources se terminent

105

J'ai une seule usine définie avec ngResource:

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

Je fais plusieurs appels à la méthode de requête définie sur cette usine. Les appels peuvent se produire de manière asynchrone, mais je dois attendre la fin des deux appels avant de continuer:

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
    };
});

Existe-t-il un moyen de faire cela avec les usines AngularJS définies avec ngResource, similaire à la fonctionnalité $ .when (). Then () de jQuery? Je préférerais ne pas ajouter jQuery à mon projet actuel.

Nathan Donze
la source

Réponses:

201

Vous voudrez utiliser des promesses et $ q.all () .

Fondamentalement, vous pouvez l'utiliser pour envelopper tous vos appels $ resource ou $ http car ils renvoient des promesses.

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
la source
17
Les ressources ne renvoient pas de promesses, elles renvoient des objets à remplir dans le futur. Cependant, dans la version unstable 1.1.3, les ressources ont également des $thenpropriétés mais n'exposent aucun objet de promesse. Exposer $promisecomplètement serait en 1.1.4
Umur Kontacı
@ UmurKontacı Ce n'est malheureusement pas en angulaire 1.1.4!
nh2
Les détails sur le problème des ressources ne sont pas des promesses peuvent être trouvés dans ce fil et dans cette demande d'extraction .
nh2
1
Cette réponse montre comment l'écrire une fois qu'elle est implémentée.
nh2
3
Votre réponse est très utile et je pense que c'est le moyen le plus judicieux de convertir des ressources en promesses dans l'angulaire actuel. Il peut être utile d'ajouter que dans la documentation de $q, à laquelle vous avez lié, cela garantit que le tableau de résultats est dans le même ordre que le tableau de promesse.
NH2
20

Je pense qu'une meilleure solution est:

$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...
});
Contes Mundim Andrade Porto
la source
1
Pour moi, j'ai travaillé sans $ promise à la fin ... Tout comme: Account.query ({type: 'billing'}), Account.query ({type: 'shipping'})
georgeos
12

La solution de Ben Lesh est la meilleure mais elle n'est pas complète. Si vous devez gérer des conditions d'erreur - et, oui, vous le faites - alors vous devez utiliser la catchméthode sur l'API de promesse comme ceci:

$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...

});

Si vous ne définissez pas catchet que toutes vos promesses échouent, la thenméthode ne s'exécutera jamais et laissera donc probablement votre interface dans un mauvais état.

Nick A. Watts
la source