AngularJS обновляет представление с изменениями сервиса / модели, используя обещания $ q

#angularjs #promise #angular-promise

#angularjs #обещание #angular-обещание

Вопрос:

Я пытаюсь загрузить данные из сервиса и обновить представление, используя $ q, но это не работает. Это работает, если я помещаю http-вызов внутри контроллера, но я бы предпочел, чтобы он был частью сервиса.

Любая помощь? Кроме того, есть ли лучший способ сделать это вместо обещаний?

Демонстрация и код ниже.

———- Демонстрационная ссылка на скрипку ———-

Вид

 <div ng-init="getData()">
  <div ng-repeat="item in list">{{item.name}}</div>
</div>
  

Контроллер

 .controller('ctrl', ['$scope', 'dataservice', '$q', function ($scope, dataservice, $q) {

  $scope.list = dataservice.datalist;

  var loadData = function () {
    dataservice.fakeHttpGetData();
  };

  var setDataToScope = function () {
    $scope.list = dataservice.datalist;
  };

  $scope.getData = function () {
    var defer = $q.defer();
    defer.promise.then(setDataToScope());
    defer.resolve(loadData());
  };

}])
  

Обслуживание

 .factory('dataservice', ['$timeout', function ($timeout) {

  // view displays this list at load 
  this.datalist = [{'name': 'alpha'}, {'name': 'bravo'}];

  this.fakeHttpGetData = function () {
    $timeout(function () {

      // view should display this list after 2 seconds
      this.datalist = [{'name': 'charlie'}, {'name': 'delta'}, {'name': 'echo'}];
    },
    2000);
  };

  return this;
}]);
  

Ответ №1:

Нет необходимости в ngInit или $ q. Вот как вы должны это сделать.

Вы также не должны подвергаться dataservice.list воздействию контроллера. Это должно быть закрытым для dataservice , которое будет содержать большую часть логики, чтобы определить, отправлять ли контроллеру существующий список или обновлять список, а затем отправлять его.

 angular.module('app', [])

        .controller('ctrl', ['$scope', 'dataservice', function ($scope, dataservice) {

            loadData();

            function loadData() {
                dataservice.fakeHttpGetData().then(function (result) {
                    $scope.list = resu<
                });
            }
        }])

        .factory('dataservice', ['$timeout', function ($timeout) {

            var datalist = [
                {
                    'name': 'alpha'
                },
                {
                    'name': 'bravo'
                }
            ];

            this.fakeHttpGetData = function () {

                return $timeout(function () {

                            // Logic here to determine what the list should be (what combination of new data and the existing list).

                            datalist =  [
                                {
                                    'name': 'charlie'
                                },
                                {
                                    'name': 'delta'
                                },
                                {
                                    'name': 'echo'
                                }
                            ];

                            return datalist;
                        },
                        2000);
            };

            return this;
        }]);
  

Ответ №2:

Во-первых, не используйте ng-init таким образом. Согласно документам:

Единственное подходящее использование ngInit — это сглаживание специальных свойств ngRepeat, как показано в демонстрации ниже. Кроме того, в этом случае для инициализации значений в области видимости следует использовать контроллеры, а не ngInit.

Во-вторых, обещания — это идеальная вещь для использования в этом случае, но вам не нужно трогать $q , так как $http вызовы возвращают обещания для вас.

Чтобы сделать это правильно, просто верните $http результат из сервиса:

 this.getDataFromService = function() {
    return $http(/* http call info */);
};
  

Затем внутри вашего контроллера:

 dataservice.getDataFromService().then(function(result){
    $scope.list = result.data;
});    
  

Также вот обновленная скрипка: http://jsfiddle.net/RgwLR /

Имейте в виду, что $q.when() просто обертывает заданное значение в обещание (имитируя ответ из $http вашего примера).

Комментарии:

1. IIRC, результатом в .then HTTP является сам запрос, и вы хотите result.data

2. Да, но скрипка не выполняет HTTP-запрос, не так ли :)?

3. Ах да, забыл, что он добавляет кучу дополнений.