Яка найкраща практика здійснення дзвінків AJAX в Angular.js?


151

Я читав цю статтю: http://eviltrout.com/2013/06/15/ember-vs-angular.html

І воно сказало:

Через відсутність умов, мені цікаво, скільки кутових проектів покладаються на погані практики, такі як дзвінки AJAX безпосередньо в контролерах? Через інжекцію залежності розробники вводять параметри маршрутизатора в директиви? Чи починаючі розробники AngularJS збираються структурувати свій код таким чином, який досвідчений розробник AngularJS вважає ідіоматичним?

Я фактично $httpтелефоную з мого контролера Angular.js. Чому це погана практика? Яка найкраща практика для здійснення $httpдзвінків тоді? і чому?


12
+1 за посилання на цікавий пост, в якому порівнюються вугілля та кутовий вугал.
Chandermani

Я так само замислювався щодо кращих практик Angular
Далорцо,

Також додаток також перевіряє API, чи не пропустили речі: docs.angularjs.org/api/ng/service/$http
Крістоф Руссі

Відповіді:


174

EDIT: Ця відповідь в основному була зосереджена на версії 1.0.X. Щоб запобігти плутанині, її змінено, щоб відобразити найкращу відповідь на ВСІ поточні версії Angular на сьогодні, 2013-12-05.

Ідея полягає у створенні сервісу, який повертає обіцянку повернутим даним, а потім зателефонуйте до цього у свій контролер та обробіть там обіцянку для заповнення вашого $ властивості.

Сервіс

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

Контролер:

Обробіть then()метод обіцянки та вийміть із нього дані. Встановіть властивість $ range і зробіть все, що вам може знадобитися.

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

Роздільна здатність щодо перегляду (лише 1.0.X):

У Angular 1.0.X, ціль оригінальної відповіді тут, обіцянки отримають спеціальну обробку з боку Вид. Коли вони вирішаться, їх розв’язане значення буде прив’язане до подання. Це було знято в 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властивість у шаблоні. Якщо ви використовували те саме властивість поза шаблоном (наприклад, в іншій функції), об'єкт, що зберігається там, все ще є об'єктом, який обіцяє.
Кларк Пан

1
В даний час я використовую цю схему в новому кутовому додатку, однак на грубій сторінці мені цікаво, як отримати доступ до властивості, яку я прив’язав до області, у цьому прикладі, якщо я хотів взяти дані з getFoos та розмістити зміни в це. якщо я спробую отримати доступ до $ range.foos у своєму оновленні, у мене є об’єкт обіцянки, а не дані, я можу побачити, як отримати дані в самому об’єкті, але це здається дійсно hacky.ideas?
Келлі Мілліган

5
@KellyMilligan, у цій моделі саме обов'язковість знає, що робити з обіцянкою. Якщо вам необхідно отримати доступ до об'єкта з будь-якої іншої, ви будете мати , щоб впоратися з .then()обітниці і помістити значення в $ рамки ...myService.getFoos().then(function(value) { $scope.foos = value; });
Бен Леш

1
Просто оновлення цієї методики, станом на 1.2.0-rc.3, автоматичне скасування обіцянок застаріло, тому ця техніка більше не працюватиме.
Кларк Пан

2
Нещодавно тут з’явилося пару голосів, імовірно, тому, що вони більше не відповідали останній версії Angular. Я оновив відповідь, щоб це відобразити.
Бен Леш

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) {

1

Я поставив відповідь для того, хто захотів повністю загальний веб-сервіс у Angular. Я рекомендую просто підключити його, і він подбає про всі ваші дзвінки через веб-службу, не потрібно кодувати їх самі. Відповідь тут:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.