Я пытаюсь сделать красивое и удобное приложение угловатым, и я в той части, где я позволяю пользователю знать, что материал загружается, когда я делаю запросы 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
Если вы хотите, чтобы ваш контроллер подождал, вам нужно правильно настроить параметр 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;
});
Все эти ошибки исходят из того, что пытались преобразовать асинхронный вызов в синхронный. Это просто невозможно.
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;
});
});
Вы можете вводить свою услугу в любые контроллеры, поэтому вам не нужно передавать ее с разрешения.
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.
Кстати, ваш сервис не будет работать без обещаний, как было предложено другим пользователем в вашем комментарии.
$http
я должен сказать, что я не очень люблю это, не возвращая нормальный объект обещания. Из-за этого я обычно склоняюсь скрывать http-вызов внутри службы, которая только когда-либо возвращает реальные обещания (если их можно так назвать).