在Angular.js中进行AJAX调用的最佳实践是什么?


151

我正在阅读这篇文章:http : //eviltrout.com/2013/06/15/ember-vs-angular.html

它说,

由于缺乏约定,我想知道有多少Angular项目依赖于不良行为,例如直接在控制器内进行AJAX调用?由于依赖注入,开发人员是否将路由器参数注入指令中?AngularJS新手开发人员是否会以经验丰富的AngularJS开发人员认为惯用的方式来构造代码?

我实际上是$http从Angular.js控制器进行调用。为什么这是一个坏习惯?那么$http拨打电话的最佳做法是什么?为什么呢?


12
+1是指有趣的帖子,比较了ember和angularjs。
Chandermani


另外,还可以检查API是否包含您可能错过的内容:docs.angularjs.org/api/ng/service/$http
Christophe Roussy

Answers:


174

编辑:这个答案主要集中在版本1.0.X。为避免混淆,自2013年12月5日起,已对其进行更改以反映所有当前Angular版本的最佳答案。

这个想法是创建一个向返回的数据返回一个承诺的服务,然后在您的控制器中调用该服务并在那里处理该承诺以填充$ scope属性。

服务

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

控制器:

处理promise的then()方法并从中获取数据。设置$ scope属性,然后执行您可能需要做的其他事情。

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

视野中的承诺解决方案(仅1.0.X版):

在此处原始答案的目标Angular 1.0.X中,Promise将由View进行特殊处理。当他们解析时,其解析值将绑定到视图。在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();
});

4
只需提及,这仅在您$scope.foos在模板中使用属性时才有效。如果要在模板外部(例如,在另一个函数中)使用同一属性,则存储在其中的对象仍然是promise对象。
克拉克潘

1
我目前在新的角度应用程序中使用此模式,但是我想知道在粗糙页面中如何访问绑定到范围的属性,在本示例中,如果我想从getFoos中获取数据并将更改发布到它。如果我尝试在更新中访问$ scope.foos,那么我将拥有promise对象而不是数据,我可以看到如何在对象本身中获取数据,但这似乎真的很hacky.ideas吗?
凯利米利根

5
@KellyMilligan,在这种模式下,绑定是知道如何处理承诺的。如果您需要从其他任何地方访问对象,则必须处理.then()promise的内容并将其值放在$ scope中……myService.getFoos().then(function(value) { $scope.foos = value; });
Ben Lesh 2013年

1
从1.2.0-rc.3版本开始,仅对此技术进行了更新,已弃用了promises的自动展开功能,因此该技术将不再起作用。
克拉克·潘

2
最近在这里遭到了两次投票,大概是因为它不再符合最新版本的Angular。我已经更新了答案以反映这一点。
Ben Lesh 2013年

45

最佳做法是将$http调用抽象为“服务”,以向控制器提供数据:

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

$http像这样抽象化调用,将使您可以在多个控制器之间重用此代码。当与该数据交互的代码变得更加复杂时,这很有必要,也许您希望在控制器中使用该数据之前先对其进行处理,并缓存该过程的结果,这样您就不必花费时间来重新处理它。

您应该将“服务”视为应用程序可以使用的数据的表示形式(或模型)。


9

可接受的答案是给我$http is not defined错误,所以我必须这样做:

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

主要区别是以下行:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.