处理服务中的$ http响应
我最近发布了关于我在SO所面临的问题的详细描述。 因为我无法发送实际的$http
请求,所以我使用timeout来模拟asynchronous行为。 从@Gloopy的帮助下,从我的模型查看数据的function是正确的
现在,当我使用$http
而不是$timeout
(本地testing)时,我可以看到asynchronous请求成功, data
在我的服务中填充了json响应。 但是,我的观点并没有更新。
在这里更新了Plunkr
这是一个你想要的plunk: http ://plnkr.co/edit/TTlbSv?p=preview
这个想法是,你直接使用承诺和他们的“then”函数来操作和访问asynchronous返回的响应。
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; }); });
这是一个稍微复杂的版本,caching请求,所以你只有第一次( 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; }); }; });
让它变得简单。 这很简单
- 在您的服务中返回
promise
(不需要在服务中使用) -
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; }); });
由于它是asynchronous的,所以$scope
在ajax调用完成之前就获取了数据。
您可以在您的服务中使用$q
来创buildpromise
并将其交还给控制器,并且控制器在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(); }); });
托什shimayama有一个解决scheme,但你可以简化很多,如果你使用的事实,$ 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会自动把已解决的awesomeFruits
放到$scope.fruits
。
将UI绑定到数组时,您需要确保通过将长度设置为0并将数据推送到数组中,直接更新同一数组。
而不是(这将设置一个不同的数组引用您的用户界面将不知道的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]); } }); };
这是一个小提琴 ,显示设置一个新的数组与清空和添加到现有的区别。 我无法让你的plnkr工作,但希望这对你有用!
与此相关,我经历了一个类似的问题,但没有获得或由Angular发布,但由第三方(在我的情况下Chrome扩展)的扩展。
我面对的问题是,Chrome扩展不会返回then()
所以我无法做到这一点上面的解决scheme,但结果仍然是asynchronous。
所以我的解决scheme是创build一个服务,并进行callback
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); }); });
希望这可以帮助别人得到同样的问题。
我已阅读http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/ [AngularJS允许我们通过直接在作用域上放置一个承诺来简化我们的控制器逻辑,而不是手动处理已解决成功callback中的值。]
所以简单而方便:)
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(); });
希望这个帮助
我有同样的问题,但当我在互联网上冲浪,我知道$ http默认情况下返回一个承诺,那么我可以在返回“数据”后用“then”来使用它。 看代码:
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; }); });
我真的不喜欢这样一个事实:由于“承诺”做事的方式,使用$ http的服务的用户必须“知道”如何解压缩响应。
我只是想调用一些东西,并获取数据,类似于旧的$scope.items = Data.getData();
方式, 现在已经被弃用了 。
我试了一会儿,并没有提出一个完美的解决scheme,但这里是我的最佳镜头( 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 }; });
我已经可以发现的缺陷是
- 你必须传入你想要添加数据的对象,这在Angular中不是一个直观的或通用的模式
-
getData
只能以obj
的forms接受obj
参数(尽pipe它也可以接受数组),这对许多应用程序来说都不是问题,但是它是一个痛苦的限制 - 你必须准备input对象
$scope.data
= {}
,使其成为一个对象(本质上是$scope.clearData()
),或者= []
为一个数组,或者它不起作用已经不得不假设什么数据来了)。 我试图在getData
做这个准备步骤,但没有运气。
不过,它提供了一个模式,它可以去掉控制器的“promise unwrap”样板文件,并且可以在你想要使用$ http获得的某些数据在多个地方同时保持DRY的情况下使用。
至于在服务中caching响应,这里的另一个版本比我目前看到的更直接:
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; }); })(); });
此服务将返回caching的数据或$http.get
;
dataStorage.then(function(data) { $scope.data = data; },function(e){ console.log('err: ' + e); });
请尝试下面的代码
您可以将控制器(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; }); } } }());