#angularjs #promise #angular-promise
#angularjs #обещание #angular-обещание
Вопрос:
Я пытаюсь загрузить данные из сервиса и обновить представление, используя $ q, но это не работает. Это работает, если я помещаю http-вызов внутри контроллера, но я бы предпочел, чтобы он был частью сервиса.
Любая помощь? Кроме того, есть ли лучший способ сделать это вместо обещаний?
Демонстрация и код ниже.
———- Демонстрационная ссылка на скрипку ———-
Вид
<div ng-init="getData()">
<div ng-repeat="item in list">{{item.name}}</div>
</div>
Контроллер
.controller('ctrl', ['$scope', 'dataservice', '$q', function ($scope, dataservice, $q) {
$scope.list = dataservice.datalist;
var loadData = function () {
dataservice.fakeHttpGetData();
};
var setDataToScope = function () {
$scope.list = dataservice.datalist;
};
$scope.getData = function () {
var defer = $q.defer();
defer.promise.then(setDataToScope());
defer.resolve(loadData());
};
}])
Обслуживание
.factory('dataservice', ['$timeout', function ($timeout) {
// view displays this list at load
this.datalist = [{'name': 'alpha'}, {'name': 'bravo'}];
this.fakeHttpGetData = function () {
$timeout(function () {
// view should display this list after 2 seconds
this.datalist = [{'name': 'charlie'}, {'name': 'delta'}, {'name': 'echo'}];
},
2000);
};
return this;
}]);
Ответ №1:
Нет необходимости в ngInit или $ q. Вот как вы должны это сделать.
Вы также не должны подвергаться dataservice.list
воздействию контроллера. Это должно быть закрытым для dataservice
, которое будет содержать большую часть логики, чтобы определить, отправлять ли контроллеру существующий список или обновлять список, а затем отправлять его.
angular.module('app', [])
.controller('ctrl', ['$scope', 'dataservice', function ($scope, dataservice) {
loadData();
function loadData() {
dataservice.fakeHttpGetData().then(function (result) {
$scope.list = resu<
});
}
}])
.factory('dataservice', ['$timeout', function ($timeout) {
var datalist = [
{
'name': 'alpha'
},
{
'name': 'bravo'
}
];
this.fakeHttpGetData = function () {
return $timeout(function () {
// Logic here to determine what the list should be (what combination of new data and the existing list).
datalist = [
{
'name': 'charlie'
},
{
'name': 'delta'
},
{
'name': 'echo'
}
];
return datalist;
},
2000);
};
return this;
}]);
Ответ №2:
Во-первых, не используйте ng-init
таким образом. Согласно документам:
Единственное подходящее использование ngInit — это сглаживание специальных свойств ngRepeat, как показано в демонстрации ниже. Кроме того, в этом случае для инициализации значений в области видимости следует использовать контроллеры, а не ngInit.
Во-вторых, обещания — это идеальная вещь для использования в этом случае, но вам не нужно трогать $q
, так как $http
вызовы возвращают обещания для вас.
Чтобы сделать это правильно, просто верните $http
результат из сервиса:
this.getDataFromService = function() {
return $http(/* http call info */);
};
Затем внутри вашего контроллера:
dataservice.getDataFromService().then(function(result){
$scope.list = result.data;
});
Также вот обновленная скрипка: http://jsfiddle.net/RgwLR /
Имейте в виду, что $q.when()
просто обертывает заданное значение в обещание (имитируя ответ из $http
вашего примера).
Комментарии:
1. IIRC, результатом в
.then
HTTP является сам запрос, и вы хотитеresult.data
2. Да, но скрипка не выполняет HTTP-запрос, не так ли :)?
3. Ах да, забыл, что он добавляет кучу дополнений.