Угловой сервис возвращает пустой объект

0

Я пытаюсь сделать красивое и удобное приложение угловатым, и я в той части, где я позволяю пользователю знать, что материал загружается, когда я делаю запросы ajax. То, что я пытаюсь выполнить: я хочу создать службу, которая обрабатывает извлечение данных инициализации и передает данные в качестве объекта моему контроллеру, когда он станет доступным. Конечно, представление не отображается до тех пор, пока не будут доступны все исходные данные, которые нужны моему контроллеру. Вот что у меня есть:

app.js

var Application = angular.module('ReporterApplication', ['ngRoute']);

Application.service('Initialize', ['$http', '$q', '$timeout', function($http, $q, $timeout)
{   

    this.serverData = function() 
    {
        $http.get('/packing/scan.action')
            .success(function(data)
            {                         
                return data;
            })
            .error(function(data)
            {
                return data;
            });

    };   

}])


Application.config(['$routeProvider', '$interpolateProvider',

    function($routeProvider, $interpolateProvider) {

        $interpolateProvider.startSymbol('<%');
        $interpolateProvider.endSymbol('%>');

        $routeProvider

            .when('/packing/scan.html', {
                templateUrl: 'packing/scan.html',
                controller: 'PackingScanController as packer',
                resolve: {

                    initData : 'Initialize'   .... etc more code

scan.js

Application.controller('PackingScanController', ['$scope', '$http', 'initData', function($scope, $http, initData) {

    var packer = this;

    packer.packedToday = initData.serverData(); ... etc more code
Теги:

3 ответа

1
Лучший ответ

Если вы хотите, чтобы ваш контроллер подождал, вам нужно правильно настроить параметр resolve. Для этого вам нужно, чтобы ваша служба вернула обещание, иначе маршрутизатор не будет ждать.

resolve - {Object.<string, function>=} - необязательная карта зависимостей, которые должны быть введены в контроллер. Если какая-либо из этих зависимостей является обещанием, маршрутизатор будет ждать, пока все они будут разрешены или один будет отклонен до того, как будет создан экземпляр контроллера.


Здесь упрощенный пример:

app.service('Initialize', ['$http', function($http) {
  this.serverData = function()
  {
    // return the http promise
    return $http
      .get('config.json')
      // use success/error if needed
      .then(function (response) {
        // make sure, only the response data is used
        return response.data;
      })
    ;
  };
}]);

app.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/', {
      template: '<pre>{{ main.initData|json }}</pre>',
      controller: 'MainCtrl as main',
      resolve: {
        // configure with DI
        initData: ['Initialize', function (Initialize) {
          // call the service method, and return the promise
          return Initialize.serverData();
        }]
      }
    })
  ;
}]);

app.controller('MainCtrl', function (initData) {
  // initData will be loaded
  this.initData = initData;
});

demo: http://plnkr.co/edit/sOwyHz4yMvwujBWYzOn0?p=preview

  • 0
    Большое спасибо, ваш пример был хорошо объяснен и довольно прост. Могу ли я как-то передать указанное обещание непосредственно в объект разрешения? Потому что я хотел бы сохранить как можно меньше логики в конфигурации, потому что будет все больше и больше маршрутов. Кроме того, почему невозможно работать с успехом и ошибкой вместо get? Я попробовал это, и он возвращает объект полностью
  • 0
    @JonathanSzekely Несколько замечаний: лично я использую ui-router , с этим есть несколько синтаксических ярлыков относительно того, как можно разрешать зависимости. Что касается $http я должен сказать, что я не очень люблю это, не возвращая нормальный объект обещания. Из-за этого я обычно склоняюсь скрывать http-вызов внутри службы, которая только когда-либо возвращает реальные обещания (если их можно так назвать).
Показать ещё 2 комментария
0

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

serverData() больше ничего не возвращает. Оператор возвращаемых данных не возвращается из serverData(). Его возврат из анонимной функции обратного вызова передается then().

Анонимный обратный вызов не вызывается немедленно. Его вызывается, когда доступен ответ. И это происходит задолго после возврата serverData().

Итак, 1. один способ: использовать обратные вызовы

Application.service('initdata',function($http){
    var serverData = function(callback){
        $http.get('/packing/scan.action').then(function(response){
            callback(response.data);
        });
   };

   return {
       serverData: serverData
   };
});

Application.controller('PackingScanController',function(initdata){
    initdata.serverData(function(serverdata){
       $scope.serverdata = serverdata;
    });
});

2. Второй способ просто вернуть обещание HTTP, и пусть контроллер справится с ним.

Application.service('initdata',function($http){
    var serverData = function(){
        return $http.get('/packing/scan.action');
    };

    return {
        serverData: serverData
    };  
});

Application.controller('PackingScanController',function(initdata){
    initdata.serverData().then(function(response){
        $scope.serverdata = response.data;
    });
});

3. Вы также можете вернуть обещание serverData вместо того, чтобы возвращать обещание ответа на HTTP.

Application.service('initdata',function($http){
    var serverData = function() {
        var defer = $q.defer();

        $http.get('/api/ponies').then(function(response) {
            defer.resolve(response.data);
        });

        return defer.promise;
    };

    return {
        serverData: serverData
    };  
});

Application.controller('PackingScanController',function(initdata){
    initdata.serverData().then(function(response){
        $scope.serverdata = response.data;
    });
});
0

Вы можете вводить свою услугу в любые контроллеры, поэтому вам не нужно передавать ее с разрешения.

Application.controller('PackingScanController', ['$scope', '$http', 'Initialize', function($scope, $http, Initialize)

Для загрузчика обычно то, что я делаю, я проверяю доступность данных в шаблоне с помощью ng-show

<div ng-show="!data">Loading...</div>
<div ng-show="!!data" ng-repeat="d in data">...</div>

В любое время, когда вам нужен загрузчик для показа, просто установите для параметра $ scope.data значение null и перейдите к службе API.

Кстати, ваш сервис не будет работать без обещаний, как было предложено другим пользователем в вашем комментарии.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню