¿Cuál es la mejor práctica para hacer una llamada AJAX en Angular.js?

Estaba leyendo este artículo: http://eviltrout.com/2013/06/15/ember-vs-angular.html

Y dijo:

Debido a su falta de convenciones, me pregunto cuántos proyectos de Angular se basan en malas prácticas, como las llamadas AJAX directamente dentro de los controladores. Debido a la dependency injection, ¿los desarrolladores están inyectando parámetros de enrutadores en directivas? ¿Los desarrolladores noveles de AngularJS van a estructurar su código de una manera que un desarrollador experimentado de AngularJS cree que es idiomático?

De hecho, estoy haciendo llamadas de $http desde mi controlador Angular.js. ¿Por qué es una mala práctica? ¿Cuál es la mejor práctica para hacer llamadas de $http , entonces? ¿y por qué?

EDITAR: Esta respuesta se centró principalmente en la versión 1.0.X. Para evitar confusiones, se está modificando para reflejar la mejor respuesta para TODAS las versiones actuales de Angular a partir de hoy, 2013-12-05.

La idea es crear un servicio que devuelva una promesa a los datos devueltos, luego llamar a eso en su controlador y manejar la promesa allí para poblar su propiedad de $ scope.

El servicio

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

El controlador:

Maneje el método then() la promesa y obtenga los datos de ella. Establezca la propiedad $ scope y haga lo que necesite hacer.

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

Resolución de Promesa In-View (1.0.X solamente):

En Angular 1.0.X, el objective de la respuesta original aquí, las promesas recibirán un trato especial por parte de la Vista. Cuando se resuelvan, su valor resuelto estará vinculado a la vista. Esto ha quedado obsoleto en 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(); }); 

La mejor práctica sería resumir la llamada $http en un ‘servicio’ que proporciona datos a su controlador:

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

Resumir la llamada de $http esta manera le permitirá reutilizar este código en múltiples controladores. Esto se vuelve necesario cuando el código que interactúa con estos datos se vuelve más complejo, quizás desee procesar los datos antes de usarlos en su controlador, y almacenar en caché el resultado de ese proceso para que no tenga que perder tiempo reprocesándolo.

Debería pensar en el ‘servicio’ como una representación (o modelo) de datos que su aplicación puede usar.

La respuesta aceptada me daba el error $http is not defined así que tuve que hacer esto:

 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 principal diferencia es esta línea:

 policyService.service('PolicyService', ['$http', function ($http) { 

Puse una respuesta para alguien que quería un servicio web totalmente genérico en Angular. Recomiendo simplemente enchufarlo y se ocupará de todas las llamadas a su servicio web sin necesidad de codificarlas todas ustedes. La respuesta está aquí:

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