我最近在SO上发布了我所面临的here问题的详细说明。由于我无法发送实际的$http
请求,因此我使用超时来模拟异步行为。在@Gloopy
现在,当我使用$http
而不是$timeout
(在本地测试)时,我可以看到异步请求成功,data
在我的服务中填充了json响应。但是,我的观点并未更新。
更新了Plunkr here
答案 0 :(得分:417)
这是一个可以满足您需求的Plunk:http://plnkr.co/edit/TTlbSv?p=preview
这个想法是你直接使用promises和它们的“then”函数来操作和访问异步返回的响应。
app.factory('myService', function($http) {
var myService = {
async: function() {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('test.json').then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response);
// The return value gets picked up by the then in the controller.
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
这是一个稍微复杂的版本,用于缓存请求,因此您只能第一次(http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview):
app.factory('myService', function($http) {
var promise;
var myService = {
async: function() {
if ( !promise ) {
// $http returns a promise, which has a then function, which also returns a promise
promise = $http.get('test.json').then(function (response) {
// The then function here is an opportunity to modify the response
console.log(response);
// The return value gets picked up by the then in the controller.
return response.data;
});
}
// Return the promise to the controller
return promise;
}
};
return myService;
});
app.controller('MainCtrl', function( myService,$scope) {
$scope.clearData = function() {
$scope.data = {};
};
$scope.getData = function() {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
};
});
答案 1 :(得分:82)
让它变得简单。它就像
一样简单promise
(无需在服务中使用then
)then
演示。 http://plnkr.co/edit/cbdG5p?p=preview
var app = angular.module('plunker', []);
app.factory('myService', function($http) {
return {
async: function() {
return $http.get('test.json'); //1. this returns promise
}
};
});
app.controller('MainCtrl', function( myService,$scope) {
myService.async().then(function(d) { //2. so you can use .then()
$scope.data = d;
});
});
答案 2 :(得分:58)
因为它是异步的,所以$scope
在ajax调用完成之前获取数据。
您可以在服务中使用$q
创建promise
并将其还原
控制器和控制器在then()
的{{1}}调用中获得结果。
在您的服务中,
promise
然后,在你的控制器中:
app.factory('myService', function($http, $q) {
var deffered = $q.defer();
var data = [];
var myService = {};
myService.async = function() {
$http.get('test.json')
.success(function (d) {
data = d;
console.log(d);
deffered.resolve();
});
return deffered.promise;
};
myService.data = function() { return data; };
return myService;
});
答案 3 :(得分:23)
shoshyama有一个解决方案,但是如果你使用$ http返回promises并且promises可以返回一个值的事实你可以简化很多:
app.factory('myService', function($http, $q) {
myService.async = function() {
return $http.get('test.json')
.then(function (response) {
var data = reponse.data;
console.log(data);
return data;
});
};
return myService;
});
app.controller('MainCtrl', function( myService,$scope) {
$scope.asyncData = myService.async();
$scope.$watch('asyncData', function(asyncData) {
if(angular.isDefined(asyncData)) {
// Do something with the returned data, angular handle promises fine, you don't have to reassign the value to the scope if you just want to use it with angular directives
}
});
});
coffeescript中的一个小演示:http://plunker.no.de/edit/ksnErx?live=preview
您的插件使用我的方法进行了更新:http://plnkr.co/edit/mwSZGK?p=preview
答案 4 :(得分:7)
我认为更好的方法是这样的:
服务:
app.service('FruitsManager',function($q){
function getAllFruits(){
var deferred = $q.defer();
...
// somewhere here use: deferred.resolve(awesomeFruits);
...
return deferred.promise;
}
return{
getAllFruits:getAllFruits
}
});
在控制器中你可以简单地使用:
$scope.fruits = FruitsManager.getAllFruits();
Angular会自动将已解决的awesomeFruits
放入$scope.fruits
。
答案 5 :(得分:6)
我遇到了同样的问题,但是当我在网上冲浪时,我明白$ http默认返回一个承诺,然后我可以用#34;然后"返回"数据"。看看代码:
app.service('myService', function($http) {
this.getData = function(){
var myResponseData = $http.get('test.json').then(function (response) {
console.log(response);.
return response.data;
});
return myResponseData;
}
});
app.controller('MainCtrl', function( myService, $scope) {
// Call the getData and set the response "data" in your scope.
myService.getData.then(function(myReponseData) {
$scope.data = myReponseData;
});
});
答案 6 :(得分:4)
将UI绑定到数组时,您需要确保通过将长度设置为0并将数据推送到数组中来直接更新相同的数组。
而不是这个(设置一个不同的数组引用到你的UI不知道的data
):
myService.async = function() {
$http.get('test.json')
.success(function (d) {
data = d;
});
};
试试这个:
myService.async = function() {
$http.get('test.json')
.success(function (d) {
data.length = 0;
for(var i = 0; i < d.length; i++){
data.push(d[i]);
}
});
};
Here is a fiddle显示设置新阵列与清空和添加到现有阵列之间的区别。我无法让你的plnkr工作,但希望这适合你!
答案 7 :(得分:4)
与此相关的我遇到了类似的问题,但不是由Angular提出或发布,而是由第三方制作的扩展(在我的案例中为Chrome扩展)。
我遇到的问题是Chrome扩展程序不会返回then()
,所以我无法按照上述解决方案的方式执行操作,但结果仍然是异步。
所以我的解决方案是创建服务并继续回调
app.service('cookieInfoService', function() {
this.getInfo = function(callback) {
var model = {};
chrome.cookies.get({url:serverUrl, name:'userId'}, function (response) {
model.response= response;
callback(model);
});
};
});
然后在我的控制器中
app.controller("MyCtrl", function ($scope, cookieInfoService) {
cookieInfoService.getInfo(function (info) {
console.log(info);
});
});
希望这可以帮助其他人解决同样的问题。
答案 8 :(得分:4)
我看过http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/ [AngularJS允许我们通过直接在作用域上放置一个promise来简化我们的控制器逻辑,而不是在成功回调中手动处理已解析的值。]
如此简单而方便:)
var app = angular.module('myApp', []);
app.factory('Data', function($http,$q) {
return {
getData : function(){
var deferred = $q.defer();
var promise = $http.get('./largeLoad').success(function (response) {
deferred.resolve(response);
});
// Return the promise to the controller
return deferred.promise;
}
}
});
app.controller('FetchCtrl',function($scope,Data){
$scope.items = Data.getData();
});
希望这个帮助
答案 9 :(得分:2)
我真的不喜欢这样一个事实,因为&#34;承诺&#34;服务方式,使用$ http的服务的消费者必须&#34;知道&#34;关于如何解压缩响应。
我只是想调用一些内容并获取数据,类似于旧的$scope.items = Data.getData();
方式,即now deprecated。
我尝试了一段时间并没有想出一个完美的解决方案,但这是我最好的镜头(Plunker)。它可能对某人有用。
app.factory('myService', function($http) {
var _data; // cache data rather than promise
var myService = {};
myService.getData = function(obj) {
if(!_data) {
$http.get('test.json').then(function(result){
_data = result.data;
console.log(_data); // prove that it executes once
angular.extend(obj, _data);
});
} else {
angular.extend(obj, _data);
}
};
return myService;
});
然后控制器:
app.controller('MainCtrl', function( myService,$scope) {
$scope.clearData = function() {
$scope.data = Object.create(null);
};
$scope.getData = function() {
$scope.clearData(); // also important: need to prepare input to getData as an object
myService.getData($scope.data); // **important bit** pass in object you want to augment
};
});
我已经发现的缺陷是
getData
只能接受对象形式的obj
参数(尽管它也可以接受数组),这对许多应用程序来说都不是问题,但它&# 39;痛苦的限制$scope.data
准备输入对象= {}
以使其成为对象(基本上是上面$scope.clearData()
所做的),或者为数组准备= []
,或者它不会工作(我们已经不得不假设有关数据的内容)。我试着在getData
中做这个准备步骤,但没有运气。然而,它提供了一种模式,可以删除控制器&#34;承诺解包&#34;样板文件,如果你想在多个地方使用从$ http获得的某些数据,同时保持DRY,这可能很有用。
答案 10 :(得分:1)
就缓存服务中的响应而言,这是另一个看起来比我到目前为止看起来更直接的版本:
App.factory('dataStorage', function($http) {
var dataStorage;//storage for cache
return (function() {
// if dataStorage exists returned cached version
return dataStorage = dataStorage || $http({
url: 'your.json',
method: 'GET',
cache: true
}).then(function (response) {
console.log('if storage don\'t exist : ' + response);
return response;
});
})();
});
此服务将返回缓存数据或$http.get
;
dataStorage.then(function(data) {
$scope.data = data;
},function(e){
console.log('err: ' + e);
});
答案 11 :(得分:0)
请尝试以下代码
您可以拆分控制器(PageCtrl)和服务(dataService)
'use strict';
(function () {
angular.module('myApp')
.controller('pageContl', ['$scope', 'dataService', PageContl])
.service('dataService', ['$q', '$http', DataService]);
function DataService($q, $http){
this.$q = $q;
this.$http = $http;
//... blob blob
}
DataService.prototype = {
getSearchData: function () {
var deferred = this.$q.defer(); //initiating promise
this.$http({
method: 'POST',//GET
url: 'test.json',
headers: { 'Content-Type': 'application/json' }
}).then(function(result) {
deferred.resolve(result.data);
},function (error) {
deferred.reject(error);
});
return deferred.promise;
},
getABCDATA: function () {
}
};
function PageContl($scope, dataService) {
this.$scope = $scope;
this.dataService = dataService; //injecting service Dependency in ctrl
this.pageData = {}; //or [];
}
PageContl.prototype = {
searchData: function () {
var self = this; //we can't access 'this' of parent fn from callback or inner function, that's why assigning in temp variable
this.dataService.getSearchData().then(function (data) {
self.searchData = data;
});
}
}
}());