Qual é a melhor prática para fazer uma chamada AJAX em Angular.js?

Eu estava lendo este artigo: http://eviltrout.com/2013/06/15/ember-vs-angular.html

E disse:

Devido à falta de convenções, gostaria de saber quantos projetos angulares dependem de práticas ruins, como chamadas AJAX, diretamente dentro dos controladores? Devido à injeção de dependência, os desenvolvedores estão injetando parâmetros de roteador em diretivas? Os desenvolvedores novatos do AngularJS vão estruturar seu código de uma forma que um desenvolvedor experiente do AngularJS acredita ser idiomático?

Na verdade, estou fazendo chamadas $http do meu controlador Angular.js. Por que é uma má prática? Qual é a melhor prática para fazer chamadas $http ? e porque?

EDIT: Esta resposta foi principalmente foco na versão 1.0.X. Para evitar confusão, está sendo alterado para refletir a melhor resposta para TODAS as versões atuais do Angular a partir de hoje, 2013-12-05.

A idéia é criar um serviço que retorne uma promise para os dados retornados, então chame isso em seu controlador e manipule a promise de preencher sua propriedade $ scope.

O serviço

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

O controlador:

Manipule o método then() da promise e obtenha os dados dela. Defina a propriedade $ scope e faça o que você precisar fazer.

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

Resolução Promessa In-View (apenas 1.0.X):

No Angular 1.0.X, o alvo da resposta original aqui, promises, receberão tratamento especial pelo View. Quando eles resolverem, o valor resolvido será vinculado à exibição. Isso foi preterido em 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(); }); 

A melhor prática seria abstrair a chamada $http em um ‘serviço’ que fornece dados ao seu 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. }) }); 

Abstraindo a chamada $http como essa, você poderá reutilizar esse código em vários controladores. Isso se torna necessário quando o código que interage com esses dados se torna mais complexo, talvez você deseje processar os dados antes de usá-los em seu controlador e armazenar em cache o resultado desse processo para não precisar gastar tempo processando-os novamente.

Você deve pensar no ‘serviço’ como uma representação (ou modelo) dos dados que seu aplicativo pode usar.

A resposta aceita foi me dar o erro $http is not defined então eu tive que fazer isso:

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

A principal diferença é esta linha:

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

Eu coloquei uma resposta para alguém que queria um serviço web totalmente genérico em Angular. Eu recomendaria apenas conectá-lo e ele vai cuidar de todas as suas chamadas de serviço da web sem precisar codificá-las sozinho. A resposta está aqui:

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