Quelle est la meilleure pratique pour passer un appel AJAX dans Angular.js?

151

Je lisais cet article: http://eviltrout.com/2013/06/15/ember-vs-angular.html

Et il a dit,

En raison de son manque de conventions, je me demande combien de projets Angular reposent sur de mauvaises pratiques telles que les appels AJAX directement dans les contrôleurs? En raison de l'injection de dépendances, les développeurs injectent-ils des paramètres de routeur dans les directives? Les développeurs AngularJS novices vont-ils structurer leur code d'une manière qu'un développeur AngularJS expérimenté juge idiomatique?

Je passe en fait des $httpappels depuis mon contrôleur Angular.js. Pourquoi est-ce une mauvaise pratique? Quelle est alors la meilleure pratique pour passer des $httpappels? et pourquoi?

fraise
la source
12
+1 pour faire référence à un article intéressant comparant braise et angularjs.
Chandermani
Je me demandais la même chose à propos des meilleures pratiques angulaires
Dalorzo
Également un complément, vérifiez également l'API pour les choses que vous avez peut-être manquées: docs.angularjs.org/api/ng/service/$http
Christophe Roussy

Réponses:

174

EDIT: Cette réponse était principalement axée sur la version 1.0.X. Pour éviter toute confusion, il a été modifié pour refléter la meilleure réponse pour TOUTES les versions actuelles d'Angular à compter d'aujourd'hui, le 05/12/2013.

L'idée est de créer un service qui renvoie une promesse aux données renvoyées, puis de l'appeler dans votre contrôleur et de gérer la promesse là-bas pour remplir votre propriété $ scope.

Le service

module.factory('myService', function($http) {
   return {
        getFoos: function() {
             //return the promise directly.
             return $http.get('/foos')
                       .then(function(result) {
                            //resolve the promise as the data
                            return result.data;
                        });
        }
   }
});

Le controlle:

Gérez la then()méthode de la promesse et extrayez-en les données. Définissez la propriété $ scope et faites tout ce que vous pourriez avoir à faire.

module.controller('MyCtrl', function($scope, myService) {
    myService.getFoos().then(function(foos) {
        $scope.foos = foos;
    });
});

Résolution des promesses dans la vue (1.0.X uniquement):

Dans Angular 1.0.X, la cible de la réponse originale ici, les promesses recevront un traitement spécial par la vue. Lorsqu'ils se résolvent, leur valeur résolue sera liée à la vue. Cela a été abandonné dans la version 1.2.X

module.controller('MyCtrl', function($scope, myService) {
    // now you can just call it and stick it in a $scope property.
    // it will update the view when it resolves.
    $scope.foos = myService.getFoos();
});
Ben Lesh
la source
4
Juste pour mentionner, cela ne fonctionne que lorsque vous utilisez une $scope.foospropriété dans un modèle. Si vous deviez utiliser cette même propriété en dehors d'un modèle (par exemple dans une autre fonction), l'objet qui y est stocké est toujours un objet de promesse.
Clark Pan
1
J'utilise actuellement ce modèle dans une nouvelle application angulaire, mais je me demande dans une page grossière comment accéder à la propriété que j'ai liée à la portée, dans cet exemple si je voulais prendre les données de getFoos et publier des modifications sur il. si j'essaie d'accéder au $ scope.foos dans ma mise à jour, j'ai l'objet de promesse et non les données, je peux voir comment obtenir les données dans l'objet lui-même, mais cela semble vraiment vraiment hacky.ideas?
Kelly Milligan
5
@KellyMilligan, dans ce modèle, c'est la reliure qui sait quoi faire avec la promesse. Si vous avez besoin d'accéder à l'objet de n'importe où ailleurs, vous allez devoir gérer le .then()de la promesse et mettre la valeur dans le $ scope ...myService.getFoos().then(function(value) { $scope.foos = value; });
Ben Lesh
1
Juste une mise à jour sur cette technique, à partir de 1.2.0-rc.3, le désencapsulation automatique des promesses est obsolète, donc cette technique ne fonctionnera plus.
Clark Pan
2
J'ai récemment reçu quelques votes négatifs, probablement parce qu'il n'était plus conforme à la dernière version d'Angular. J'ai mis à jour la réponse pour refléter cela.
Ben Lesh
45

La meilleure pratique serait d'abstraire l' $httpappel dans un `` service '' qui fournit des données à votre responsable du traitement:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

Abstraire l' $httpappel comme celui-ci vous permettra de réutiliser ce code sur plusieurs contrôleurs. Cela devient nécessaire lorsque le code qui interagit avec ces données devient plus complexe, peut-être souhaitez-vous traiter les données avant de les utiliser dans votre contrôleur, et mettre en cache le résultat de ce processus afin que vous n'ayez pas à passer du temps à les retraiter.

Vous devez considérer le «service» comme une représentation (ou modèle) de données que votre application peut utiliser.

Clark Pan
la source
9

La réponse acceptée me donnait l' $http is not definederreur, je devais donc faire ceci:

var policyService = angular.module("PolicyService", []);
policyService.service('PolicyService', ['$http', function ($http) {
    return {
        foo: "bar",
        bar: function (params) {
            return $http.get('../Home/Policy_Read', {
                params: params
            });
        }
    };
}]);

La principale différence étant cette ligne:

policyService.service('PolicyService', ['$http', function ($http) {
user1477388
la source
1

J'ai mis une réponse pour quelqu'un qui voulait un service web totalement générique en Angular. Je recommanderais simplement de le brancher et il prendra en charge tous vos appels de service Web sans avoir besoin de tous les coder vous-même. La réponse est ici:

https://stackoverflow.com/a/38958644/5349719

cullimorer
la source