Как заставить контроллер ждать обещания решить из службы angular
У меня есть служба, которая делает запрос AJAX для бэкэнд
Сервис:
function GetCompaniesService(options)
{
this.url = '/company';
this.Companies = undefined;
this.CompaniesPromise = $http.get(this.url);
}
Контроллер:
var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(data){
$scope.Companies = data;
});
Я хочу, чтобы моя служба обрабатывала функцию ".then" вместо того, чтобы обрабатывать ее в моем контроллере, и я хочу, чтобы мой контроллер работал с этими данными из службы после того, как обещание внутри службы были разрешены.
В принципе, я хочу иметь доступ к таким данным:
var CompaniesOb = new GetCompanies();
$scope.Companies = CompaniesOb.Companies;
С разрешением обещания, которое обрабатывается внутри самой службы.
Возможно ли это? Или это единственный способ получить доступ к этому обещанию с разрешения вне службы?
Ответы
Ответ 1
Если вы хотите обработать ответ $http
в самой службе, вы можете добавить функцию then
в службу, где вы выполняете больше обработки, а затем return
от этой функции then
, например
function GetCompaniesService(options) {
this.url = '/company';
this.Companies = undefined;
this.CompaniesPromise = $http.get(this.url).then(function(response) {
/* handle response then */
return response
})
}
Но вы все равно будете использовать обещание в контроллере, но то, что вы получите, уже будет обработано в службе.
var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(dataAlreadyHandledInService) {
$scope.Companies = dataAlreadyHandledInService;
});
Ответ 2
Нет проблем для достижения этого!
Главное, что вы должны иметь в виду, это то, что вам нужно сохранить ту же ссылку на объект (а в массивах javascript - объекты) в вашей службе.
вот наш простой HTML:
<div ng-controller = "companiesCtrl">
<ul ng-repeat="company in companies">
<li>{{company}}</li>
</ul>
</div>
Вот наша реализация сервиса:
serviceDataCaching.service('companiesSrv', ['$timeout', function($timeout){
var self = this;
var httpResult = [
'company 1',
'company 2',
'company 3'
];
this.companies = ['preloaded company'];
this.getCompanies = function() {
// we simulate an async operation
return $timeout(function(){
// keep the array object reference!!
self.companies.splice(0, self.companies.length);
// if you use the following code:
// self.companies = [];
// the controller will loose the reference to the array object as we are creating an new one
// as a result it will no longer get the changes made here!
for(var i=0; i< httpResult.length; i++){
self.companies.push(httpResult[i]);
}
return self.companies;
}, 3000);
}}]);
И, наконец, контроллер, как вы этого хотели:
serviceDataCaching.controller('companiesCtrl', function ($scope, companiesSrv) {
$scope.companies = companiesSrv.companies;
companiesSrv.getCompanies();
});
Разъяснения
Как было сказано выше, трюк заключается в том, чтобы сохранить ссылку между службой и контроллером. Как только вы это уважаете, вы можете полностью привязать область своего контроллера к общедоступному свойству своей службы.
Вот скрипка, которая его обертывает.
В комментариях кода вы можете попытаться разогнать часть, которая не работает, и вы увидите, как контроллер теряет ссылку. Фактически контроллер будет продолжать ссылаться на старый массив, пока служба изменит новый.
Последнее важное: помните, что $timeout запускает $apply() на rootSCope. Именно поэтому область нашего контроллера освежает "одиночку". Без него, и если вы попытаетесь заменить его обычным setTimeout(), вы увидите, что контроллер не обновляет список компаний.
Чтобы обойти это, вы можете:
- ничего не делать, если ваши данные извлекаются с помощью $http, поскольку он вызывает $apply при успешном завершении
- wrap вы получите $timeout (..., 0);
- введите $rootSCope в службу и вызовите $apply() на нем, когда выполняется асинхронная операция.
- в контроллере добавьте $scope. $apply() в успешном завершении getCompanies().
Надеюсь, это поможет!
Ответ 3
Вы можете передать $scope в GetCompanies и установить $scope.Companies к данным в сервисе
function GetCompaniesService(options,scope)
{
this.url = '/company';
this.Companies = undefined;
this.CompaniesPromise = $http.get(this.url).then(function(res) {
scope.Companies = res;
});
}
Вы должны быть осторожны с порядком, в котором вы используете данные. Такова причина обещания начать.