Cách thực hành tốt nhất để thực hiện cuộc gọi AJAX trong Angular.js là gì?


151

Tôi đã đọc bài viết này: http://eviltrout.com/2013/06/15/ember-vs-angular.html

Và nó nói,

Do thiếu các quy ước, tôi tự hỏi có bao nhiêu dự án Angular dựa vào các thực tiễn xấu như các cuộc gọi AJAX trực tiếp trong các bộ điều khiển? Do tiêm phụ thuộc, các nhà phát triển có tiêm các tham số của bộ định tuyến vào các chỉ thị không? Các nhà phát triển AngularJS mới làm quen sẽ cấu trúc mã của họ theo cách mà một nhà phát triển AngularJS có kinh nghiệm tin là thành ngữ?

Tôi thực sự đang thực hiện $httpcuộc gọi từ bộ điều khiển Angular.js của mình. Tại sao nó là một thực hành xấu? Thực hành tốt nhất để thực hiện $httpcuộc gọi sau đó là gì? và tại sao?


12
+1 để tham khảo bài viết thú vị so sánh ember và angularjs.
Chandermani

Tôi đã tự hỏi tương tự về Thực tiễn Tốt nhất Góc
Dalorzo

Ngoài ra, một bổ sung cũng kiểm tra API cho những thứ bạn có thể đã bỏ lỡ: docs.angularjs.org/api/ng/service/$http
Christophe Roussy

Câu trả lời:


174

EDIT: Câu trả lời này chủ yếu tập trung vào phiên bản 1.0.X. Để tránh nhầm lẫn, nó được thay đổi để phản ánh câu trả lời tốt nhất cho TẤT CẢ các phiên bản hiện tại của Angular cho đến ngày hôm nay, 2013-12-05.

Ý tưởng là tạo ra một dịch vụ trả lại lời hứa cho dữ liệu được trả về, sau đó gọi nó trong bộ điều khiển của bạn và xử lý lời hứa ở đó để đưa vào thuộc tính $ scope của bạn.

Dịch vụ

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

Bộ điều khiển:

Xử lý then()phương thức của lời hứa và lấy dữ liệu ra khỏi nó. Đặt thuộc tính $ scope và làm bất cứ điều gì khác mà bạn có thể cần làm.

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

Độ phân giải hứa hẹn trong chế độ xem (chỉ 1.0.X):

Trong Angular 1.0.X, mục tiêu của câu trả lời ban đầu ở đây, hứa hẹn sẽ được đối xử đặc biệt bởi Chế độ xem. Khi họ giải quyết, giá trị được giải quyết của họ sẽ bị ràng buộc với chế độ xem. Điều này đã bị phản đối trong 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
Chỉ cần đề cập, điều này chỉ hoạt động khi bạn sử dụng một $scope.foostài sản trong một mẫu. Nếu bạn đã sử dụng cùng một thuộc tính đó bên ngoài một mẫu (ví dụ trong một hàm khác), thì đối tượng được lưu trữ vẫn còn một đối tượng hứa.
Clark Pan

1
Tôi hiện đang sử dụng mẫu này trong một ứng dụng góc cạnh mới, tuy nhiên tôi đang tự hỏi trong một trang thô sơ làm thế nào để có quyền truy cập vào thuộc tính mà tôi ràng buộc với phạm vi, trong ví dụ này nếu tôi muốn lấy dữ liệu từ getFoos và đăng các thay đổi lên nó Nếu tôi thử và truy cập $ scope.foos trong bản cập nhật của mình, tôi có đối tượng hứa và không phải dữ liệu, tôi có thể xem cách lấy dữ liệu trong chính đối tượng đó, nhưng có vẻ như nó thực sự rất hacky.ideas?
Kelly Milligan

5
@KellyMilligan, trong mô hình này, đó là ràng buộc biết phải làm gì với lời hứa. Nếu bạn cần truy cập vào đối tượng từ bất kỳ nơi nào khác, bạn sẽ phải xử lý .then()lời hứa và đặt giá trị trong phạm vi $ ...myService.getFoos().then(function(value) { $scope.foos = value; });
Ben Lesh

1
Chỉ là một bản cập nhật về kỹ thuật này, kể từ 1.2.0-rc.3, việc tự động hủy gói lời hứa đã không được chấp nhận, vì vậy kỹ thuật này sẽ không còn hoạt động.
Clark Pan

2
Gần đây có một vài downvote ở đây, có lẽ bởi vì nó không còn phù hợp với phiên bản mới nhất của Angular. Tôi đã cập nhật câu trả lời để phản ánh điều đó.
Ben Lesh

45

Cách thực hành tốt nhất là trừu tượng hóa $httpcuộc gọi thành một 'dịch vụ' cung cấp dữ liệu cho bộ điều khiển của bạn:

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

Tóm tắt $httpcuộc gọi như thế này sẽ cho phép bạn sử dụng lại mã này trên nhiều bộ điều khiển. Điều này trở nên cần thiết khi mã tương tác với dữ liệu này trở nên phức tạp hơn, có lẽ bạn muốn xử lý dữ liệu trước khi sử dụng nó trong bộ điều khiển của mình và lưu trữ kết quả của quá trình đó để bạn không phải mất thời gian xử lý lại.

Bạn nên nghĩ về 'dịch vụ' như một đại diện (hoặc Mô hình) dữ liệu mà ứng dụng của bạn có thể sử dụng.


9

Câu trả lời được chấp nhận là cho tôi $http is not definedlỗi nên tôi phải làm điều này:

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

Sự khác biệt chính là dòng này:

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

1

Tôi đặt câu trả lời cho ai đó muốn một dịch vụ web hoàn toàn chung chung trong Angular. Tôi khuyên bạn chỉ nên cắm nó vào và nó sẽ xử lý tất cả các cuộc gọi dịch vụ web của bạn mà không cần phải tự mã hóa tất cả chúng. Câu trả lời là đây:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.