(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, но первый проход через код контроллера еще не инициализировал переменную.