web-dev-qa-db-fra.com

Angularjs $ q.all

J'ai implémenté le $ q.all dans angularjs, mais je ne peux pas faire fonctionner le code. Voici mon code:

UploadService.uploadQuestion = function(questions){

        var promises = [];

        for(var i = 0 ; i < questions.length ; i++){

            var deffered  = $q.defer();
            var question  = questions[i]; 

            $http({

                url   : 'upload/question',
                method: 'POST',
                data  : question
            }).
            success(function(data){
                deffered.resolve(data);
            }).
            error(function(error){
                deffered.reject();
            });

            promises.Push(deffered.promise);
        }

        return $q.all(promises);
    }

Et voici mon contrôleur qui appelle les services:

uploadService.uploadQuestion(questions).then(function(datas){

   //the datas can not be retrieved although the server has responded    
}, 
function(errors){ 
   //errors can not be retrieved also

})

Je pense qu'il y a un problème pour mettre en place $ q.all à mon service.

104
themyth92

En javascript, il n'y a pas block-level scopes seulement function-level scopes:

Lisez cet article sur javaScript Scoping and Hoisting .

Voyez comment j'ai débogué votre code:

_var deferred = $q.defer();
deferred.count = i;

console.log(deferred.count); // 0,1,2,3,4,5 --< all deferred objects

// some code

.success(function(data){
   console.log(deferred.count); // 5,5,5,5,5,5 --< only the last deferred object
   deferred.resolve(data);
})
_
  • Lorsque vous écrivez var deferred= $q.defer(); dans une boucle for, il est hissé en haut de la fonction, cela signifie que javascript déclare cette variable dans la portée de la fonction. en dehors de _for loop_.
  • Avec chaque boucle, le dernier différé remplace le précédent, il n'y a pas de portée au niveau du bloc pour enregistrer une référence à cet objet.
  • Lorsque des rappels asynchrones (succès/erreur) sont invoqués, ils ne font référence qu'au dernier objet différé et seul celui-ci est résolu, donc $ q.all n'est jamais résolu car il attend toujours d'autres objets différés.
  • Ce dont vous avez besoin est de créer une fonction anonyme pour chaque élément que vous parcourez.
  • Comme les fonctions ont des portées, la référence aux objets différés est conservée dans un closure scope même après l'exécution des fonctions.
  • Comme #dfsq l'a commenté: Il n'est pas nécessaire de construire manuellement un nouvel objet différé puisque $ http renvoie lui-même une promesse.

Solution avec _angular.forEach_:

Voici un exemple de démonstration: http://plnkr.co/edit/NGMp4ycmaCqVOmgohN53?p=preview

_UploadService.uploadQuestion = function(questions){

    var promises = [];

    angular.forEach(questions , function(question) {

        var promise = $http({
            url   : 'upload/question',
            method: 'POST',
            data  : question
        });

        promises.Push(promise);

    });

    return $q.all(promises);
}
_

Ma méthode préférée consiste à utiliser _Array#map_:

Voici un exemple de démonstration: http://plnkr.co/edit/KYeTWUyxJR4mlU77svw9?p=preview

_UploadService.uploadQuestion = function(questions){

    var promises = questions.map(function(question) {

        return $http({
            url   : 'upload/question',
            method: 'POST',
            data  : question
        });

    });

    return $q.all(promises);
}
_
222
Ilan Frumer

$ http est aussi une promesse, vous pouvez le simplifier:

return $q.all(tasks.map(function(d){
        return $http.post('upload/tasks',d).then(someProcessCallback, onErrorCallback);
    }));
35
Zerkotin

Le problème semble être que vous ajoutez le deffered.promise quand deffered est en soi la promesse que vous devriez ajouter:

Essayez de passer à promises.Push(deffered); afin de ne pas ajouter la promesse non emballée au tableau.

 UploadService.uploadQuestion = function(questions){

            var promises = [];

            for(var i = 0 ; i < questions.length ; i++){

                var deffered  = $q.defer();
                var question  = questions[i]; 

                $http({

                    url   : 'upload/question',
                    method: 'POST',
                    data  : question
                }).
                success(function(data){
                    deffered.resolve(data);
                }).
                error(function(error){
                    deffered.reject();
                });

                promises.Push(deffered);
            }

            return $q.all(promises);
        }
12
Davin Tryon