我正在尝试使用$ q和$ http从服务器获取数据并等待直到检索到数据。在检索数据后,我想操纵它。
这是我的服务方法,它从服务器获取数据:
application
.factory('service', function ($http,$q) {
return {
fetch: function(url) {
var deferred = $q.defer();
$http.get(url).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject("An error occured while fetching items");
});
return deferred.promise;
}
};
});
使用数据的控制器如下所示:
service.fetch(url).then(function(data){
$scope.data = data;
},
function(errorMessage){
$scope.error=errorMessage;
});
$scope.data = ...manipulate data
问题在于角度在获取之前操纵数据。任何建议如何解决这个问题将非常感激。
答案 0 :(得分:4)
如果您需要处理服务呼叫中的数据,一个不错的选择是使用$http
服务中的transformResponse option。它基本上允许您在解决承诺之前完全弄乱响应。
观看此视频了解演示内容。 https://egghead.io/lessons/angularjs-transformresponse
这是一个示例转换函数。
app.factory('searchResponseTransformer', function () {
return function (data) {
data = JSON.parse(data);
if (data.length) {
// Do data manipulation here
}
return data;
};
});
然后您可以在服务中使用此转换功能。
app.factory('searchService', function ($http, searchResponseTransformer) {
return {
search: function(searchTerm) {
return $http({
method: "GET",
url: "/search",
params: { q: searchTerm },
transformResponse: searchResponseTransformer
});
}
}
});
然后您可以从控制器使用此服务。
app.controller('searchCtrl', function ($scope, searchService) {
$scope.searchTerm = "";
$scope.searchResults = [];
$scope.search = function() {
searchService
.search($scope.searchTerm)
.success(function(data) {
$scope.searchResults = data;
});
}
});
你的观点看起来像这样......
<div ng-controller="searchCtrl">
<p><input type="text" ng-model="searchTerm" ></p>
<ul>
<li ng-repeat="item in searchResults">{{item.description}}</li>
</ul>
</div>
答案 1 :(得分:2)
问题是$scope.data = ...
在service.fetch(url)
被称为而不是之后运行。调用成功回调时,AJAX调用service.fetch(url)
返回数据,因此正确的代码是:
service.fetch(url).then(
function(data) {
$scope.data = data; // keeping it for anyone else that needs it, e.g. the view
$scope.data = ... // manipulate data HERE
},
function(errorMessage) {
...
}
);
答案 2 :(得分:1)
在获取数据之前,不应该操纵数据。 Promise会立即返回,因此您的操作将被当时的回调覆盖。你应该做的是操纵当时回调中的数据:
service.fetch(url).then(function(data){
$scope.data = ...manipulate data
},
function(errorMessage){
$scope.error=errorMessage;
});
但是,要改进此代码,因为它不是非常易读,您可以创建一个服务方法来为您执行此操作。作为$ http的替代,我建议你使用Restangular。它略微面向对象。查看我写的这篇博文:
http://ath3nd.wordpress.com/2013/08/05/15/
Restangular,就像$ http一样,有承诺的概念,所以你可以这样做:
function fetch(url){
var deferred = $q.defer();
Restagular.one(url).get({})
.then(function(result){
//do your manipulation, e.g.
result.newlyCreatedProp = 'newlyCreatedProp';
deferred.resolve(result);
});
return deferred.promise;
}
然后你可以在你的控制器中做到这一点:
service.fetch().then(function(data){
$scope.data = data;
});
由于承诺会立即返回,因此会立即生效。