提前感谢您的帮助...
我有一个控制器,我用来调用API来发送密码重置链接。我已经将实际的$ http调用抽象为服务以保持控制器很薄。最初我做的是这样的事情:
angular.module('module')
.service('forgotPasswordService', ['$http', function($http) {
$http(request).then(function() {
return {}; //return some object using response
}]);
我觉得这将是最好的方法,因为它会使控制器保持尽可能薄,并将所有与服务相关的操作分开。我的问题是,从承诺内回来从来没有真正给我任何回报。我必须实际返回$ http服务调用才能获得承诺。我能够完成所有这些工作的唯一方法就是我从控制器内调用.then。
//controller
angular.module('module')
.controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {
forgotPasswordService.forgotPassword(emailAddress).then(function() {
//do stuff
}
}]);
//service
angular.module('module')
.service('forgotPasswordService', ['$http', function($http){
this.forgotPassword = function(emailAddress) {
return $http(request);
};
}]);
这对我来说感觉有点不对,因为控制器现在依赖于从服务接收回复。我可能只是在思考这个问题,但我想提出第二个意见。
这被认为是可接受的/良好做法吗?有没有替代方案可以让我实现我正在寻找的封装?
再次感谢。
答案 0 :(得分:2)
我以两种略有不同的方式与来自控制器的$http
接口。
与您一样,从服务返回$http
并与其进行交互感觉不对。
首先,我创建了服务并传递了一个成功方法和一个错误方法(回调)。
// Service
angular.module('module')
.service('forgotPasswordService', ['$http', function($http) {
function sendForgotPasswordEmail(emailAddress, success, error){
$http.post('/api/v1/resetpassword', {emailAddress:emailAddress})
.then(success, error);
}
return {
sendForgotPasswordEmail: sendForgotPasswordEmail
}
}]);
// Controller
angular.module('module')
.controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {
forgotPasswordService.sendForgotPasswordEmail(emailAddress,
function(response){ //success
// notify user of success
},
function(response){ // error
// notify user of error
});
}]);
这很有效。我用这种方式创建了一个大型应用程序,但是当我开始第二个大角度项目时,我想知道为什么我隐藏了$http
的承诺?
通过传回承诺,我可以使用其他支持promises的库。通过我的第一种方法,我无法利用其他图书馆的承诺支持。
传回$ http承诺
// Service
angular.module('module')
.service('forgotPasswordService', ['$http', function($http) {
function sendForgotPasswordEmail(emailAddress){
return $http.post('/api/v1/resetpassword', {emailAddress:emailAddress});
}
return {
sendForgotPasswordEmail: sendForgotPasswordEmail
}
}]);
// Controller
angular.module('module')
.controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {
forgotPasswordService.sendForgotPasswordEmail(emailAddress)
.then(
function(response){ //success
// notify user of success
},
function(response){ // error
// notify user of error
});
}]);
答案 1 :(得分:2)
我删除了原来的答案,我觉得自己像是一个傻瓜,说你可以用另一种方式来做。当我第一次开始角度回去检查原始代码时,我发现我在应用程序中调用then()
两次 - 一次在我的服务中我返回数据,一次在我的控制器中因为调用{ {1}}返回承诺。
事实是,您正在处理异步调用。假设在您的控制器中,您想要这样做:
$http(request).then()
$scope.foo = myService.getFoo(); // No then()
中$ http内的XmlHttpRequest是一个异步调用,意味着它调用它并继续前进。同步选项为deprecated。阻止同步HTTP调用是不良做法,因为它会占用您的用户界面。这意味着您应该在数据准备就绪时使用回调,并且仅为此创建promise API。
如果您绝对不想在控制器中使用getFoo()
,我想您可能会将范围绑定参数传递给您的服务,并让您的服务在您的调用中更新它们。我没有尝试过这个,因为它是异步的,我不确定角度是否会知道调用then()
所以你可能需要调用digest()
如果价值观不会更新。我不喜欢这样,因为我认为范围内值的控制应该由控制器而不是服务处理,但是再次 - 它&# 39;个人喜好。
很抱歉让我误入歧途 - 我遇到了同样的问题,但当我回头看时 - 我看到我使用了一个愚蠢的解决方案。
- 原始答案中的相关陈述 -
请考虑以下事项:
您希望在何处对呼叫进行错误处理,以及谁需要了解它?
您是否需要处理特定控制器中的特定故障,还是可以将它们组合到一个错误处理程序中?对于某些应用程序,我喜欢在特定位置而不是在一般模式对话框中显示错误,但是创建服务来处理所有错误并为用户弹出它们是可以接受的。
您想在哪里处理进度/忙碌指标?
如果您有一个拦截器连接所有http呼叫并广播事件以显示/隐藏繁忙指示器,那么您不必担心在控制器中处理承诺。但是,某些指令将使用promise来显示繁忙指示符,该指示符要求您将其绑定到控制器中的作用域。
对我而言,决定取决于要求和个人选择。
答案 2 :(得分:0)
尝试使用类似的回调:
angular.module('module')
.service('forgotPasswordService', ['$http', function($http) {
var recovery = function(request, callback) {
$http(request).then(function(response) {
callback(response);
})
}
return { recovery: recovery }
}]);
然后你会这样称呼:
forgotPasswordService.recovery('http://...', function(response){
console.log(response);
})