我最近发布了一篇关于我在SO面临的问题的详细描述。由于我无法发送一个实际的$http请求,所以我使用timeout来模拟异步行为。在@Gloopy的帮助下,从我的模型到视图的数据绑定工作正常
现在,当我使用$http而不是$timeout(在本地测试)时,我可以看到异步请求是成功的,数据在我的服务中被json响应填充。但是,我的观点并没有更新。
在这里更新Plunkr
我最近发布了一篇关于我在SO面临的问题的详细描述。由于我无法发送一个实际的$http请求,所以我使用timeout来模拟异步行为。在@Gloopy的帮助下,从我的模型到视图的数据绑定工作正常
现在,当我使用$http而不是$timeout(在本地测试)时,我可以看到异步请求是成功的,数据在我的服务中被json响应填充。但是,我的观点并没有更新。
在这里更新Plunkr
当前回答
Tosh shimayama有一个解决方案,但你可以简化很多,如果你使用$http返回承诺,承诺可以返回一个值:
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
其他回答
我认为更好的方式是这样的:
服务:
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会自动把解析后的awesomfruits放到$scope.fruits中。
因为它是异步的,$作用域在ajax调用完成之前获取数据。
你可以在你的服务中使用$q来创造承诺,并把它还给 控制器和控制器获得的结果在then()调用违背承诺。
为您服务,
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;
});
然后,在控制器中:
app.controller('MainCtrl', function( myService,$scope) {
myService.async().then(function() {
$scope.data = myService.data();
});
});
Tosh shimayama有一个解决方案,但你可以简化很多,如果你使用$http返回承诺,承诺可以返回一个值:
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
在将UI绑定到数组时,您需要确保通过将长度设置为0并将数据推入数组来直接更新相同的数组。
而不是这个(设置一个不同的数组引用数据,你的UI不会知道):
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]);
}
});
};
下面是一个演示,显示了设置一个新数组与清空和添加到现有数组之间的区别。我不能让你的plnkr工作,但希望这对你有用!
我真的不喜欢这样一个事实,因为“承诺”的做事方式,使用$http的服务的消费者必须“知道”如何解包响应。
我只是想调用一些东西并得到数据,类似于旧的$scope。items = Data.getData();方法,现在已弃用。
我尝试了一段时间,没有想出一个完美的解决方案,但这是我最好的办法(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
};
});
我已经发现了一些缺陷
You have to pass in the object which you want the data added to, which isn't an intuitive or common pattern in Angular getData can only accept the obj parameter in the form of an object (although it could also accept an array), which won't be a problem for many applications, but it's a sore limitation You have to prepare the input object $scope.data with = {} to make it an object (essentially what $scope.clearData() does above), or = [] for an array, or it won't work (we're already having to assume something about what data is coming). I tried to do this preparation step IN getData, but no luck.
尽管如此,它提供了一种模式,可以删除控制器的“promise unwrap”样板文件,当您想在多个地方使用从$http获得的某些数据,同时保持其DRY时,这种模式可能很有用。