(Angularjs) Как данные $http.get и хранить их в сервисе

Как вы увидите, я новичок в AngularJS, JS и в веб-разработке вообще =) очень сожалею об этом, но я стараюсь.

Я пытаюсь создать массивную веб-форму (около 200 различных полей) с контроллерами AngularJS. Мне нужен доступ от контроллера к корневому источнику данных. Команда AngularJS спрашивает, не делают ли Сервисы только для хранения данных, но я хочу сделать сервис для загрузки и сохранения данных (при запуске в .json файлы на сервере).

Услуги:

AppName.factory('MasterData', ['$rootScope', '$http', '$q', '$log', 
    function($rootScope, $http, $q, $log) {

    var responseData;
    $http.get('/getdata.php').then(function (response) {
        responseData = response.data;
        console.log(response.data);
    });

    return responseData;

}]);

Контроллер:

AppName.controller('justController', ['$scope', 'MasterData', '$log',
    function ($scope, MasterData, $log) {
        $scope.data = MasterData.justControllerSectionData;
        console.log(MasterData);
    }
]);

Возврат контроллера undefined. Но console.log из службы возвращает объект. Я чувствую, что проблема слишком проста, но я не могу найти, как ее решить:( Также я не могу использовать функцию, как .getData(), от контроллера к службе, потому что она запрашивает данные с сервера каждый раз, когда какой-либо контроллер загружается. У меня есть маршруты в приложении AngularJS с 12-14 контроллерами (полная веб-форма, разделенная по разделам), и я думаю, что это полезно, чтобы получить данные из бэкэнда один раз.

P.S. Я думаю, что существует проблема с promises, но когда я пытаюсь использовать такой код:

var defer = $q.defer();
$http.get('/getdata.php').success(function(data){
    defer.resolve(data);
});
return defer;

У меня есть объект с разрешением, отклонение и т.д. И действительно не могу понять, что я могу с ним сделать: (

Помогите мне получить данные в контроллере:)

Ответ 1

Ваш код не работает, потому что обратный вызов, который вы предоставили success() в своей службе, вызывается асинхронно; после того, как ваша служба вернулась, то есть:

Последовательность выглядит так:

  • Выполняется function в MasterData. Выполняется запрос $http.get и добавляется ответный вызов. responseData ссылается на этот обратный вызов (иначе говоря, "закрыто" ).
  • Функция возвращается из службы в ваш контроллер. responseData еще не установлен, что не мешает возврату функции родительской области.
  • $http.get завершается успешно, а responseData установлен в службе, однако недоступен для контроллера.

Если определение области вложенной функции в success() вам не понятно, я бы рекомендовал прочитать о закрытии в JavaScript (или, что еще лучше, в общем), например здесь.

Вы можете достичь своей цели с помощью такой услуги:

function($q, $http, /* ... */) {    
    return {
        getData: function() {
            var defer = $q.defer();
            $http.get('/getdata.php', { cache: 'true'})
            .then(function(response) {
                defer.resolve(response);
            });

            return defer.promise;
    };
}

Служба $http с радостью будет кэшировать ваши данные ответа, поэтому вам этого не нужно. Обратите внимание, что вам нужно получить обещание от вашего defer красного объекта, чтобы сделать эту работу.

Контроллер выглядит так:

/* omitted */ function($scope, YourService) {
    YourService.getData().then(function(response) {
        $scope.data = response.data;
    });
}

Поскольку успех обесценивается, я изменил успех до этого.

Ответ 2

Услуги должны возвращать обещание, а не данные. Это асинхронный путь.

Сначала выберите значение в методе запуска Angular. В этом примере я помещаю его в $rootScope, так как он делает его доступным для всех областей во всех контроллерах.

AppName.run(['$http', '$rootScope',
    function($http, $rootScope) {
      console.log('Run');
      $http.get('http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo')
        .success(function(data) {
          $rootScope.resource = data;
          console.log($rootScope.resource);
        });
    }
  ])

Это не обязательно, если вы не сохраните его в каком-то странном месте.

AppName.service('Resource',['$rootScope',
    function($rootScope) {
      return $rootScope.resource;
    }
  ]);

Каждая область наследует значения в $rootScope (поэтому услуга действительно не нужна.

AppName.controller('mainController', ['$scope', 'Resource',
  function($scope, Resource) {
    console.log('controller');
    console.log(Resource);
  }
]);

Внимание!!! Это значение будет недоступно только после загрузки первого контроллера. Если вы используете его в контроллере, просто помните, что вы можете привязать его к html, но первый проход через код контроллера еще не инициализировал переменную.