[英]AngularJS - rejected $http promise with $routeProvider:resolve
我试图在$routeProvider
使用resolve
来仅在$http
请求完成时显示新路由。 如果请求成功,则解析$ http.post()产生的承诺并呈现视图。 但是如果请求失败(例如,超时或内部错误),则永远不会解析承诺,并且永远不会呈现视图。 如何使用resolve
处理请求失败?
下面代码中最重要的部分是:
app.js
$routeProvider.when('/warrantyResult', {
templateUrl : 'partials/warranty-result.html',
controller : 'WarrantyResultCtrl',
resolve : {
response : [ 'Warranty', function(Warranty) {
return Warranty.sendRequest();
} ]
}
});
controllers.js
angular.module('adocDemo.controllers', []).controller('HomeCtrl', [ '$scope', function($scope) {
} ]).controller('WarrantyCtrl', [ '$scope', '$http', '$location', 'Warranty', function($scope, $http, $location, Warranty) {
$scope.submitWarranty = function() {
$scope.loading = true;
Warranty.setRequestData($scope.data);
$location.path('/warrantyResult');
};
} ]).controller('WarrantyResultCtrl', [ '$scope', 'Warranty', function($scope, Warranty) {
$scope.request = Warranty.getRequestData();
$scope.response = Warranty.getResponseData();
} ]);
services.js
angular.module('adocDemo.services', []).factory('Warranty', [ '$http', '$timeout', function($http, $timeout) {
/**
* This service is used to query the Warranty Webmethod. The sendRequest
* method is automaticcaly called when the user is redirected to
* /warrantyResult route.
*/
var isDataSet = false;
var requestData = undefined;
var responseData = undefined;
return {
setRequestData : function(data) {
//Setting the data
isDataSet = true;
},
getRequestData : function() {
return requestData;
},
sendRequest : function(data) {
if(isDataSet) {
var request = $http.post('url/to/webservice', requestData);
request.success(function(data) {
responseData = data;
});
return request;
}
},
getResponseData : function() {
return responseData;
}
};
} ]);
我知道我可以在$ http调用周围使用promise并解决它,即使请求失败,但我想知道是否有更简单的解决方案。
感谢阅读,并希望,帮助:)
我认为从resolve
做到这一点的唯一方法是手动解决Warranty.sendRequest
返回的Warranty.sendRequest
并将其重新包装在新的承诺中:
resolve : {
response : [ 'Warranty' '$q', function(Warranty, $q) {
var dfd = $q.defer();
Warranty.sendRequest().then(function(result) {
dfd.resolve({ success: true, result : result });
}, function(error) {
dfd.resolve({ success : false, reason : error });
});
return dfd.promise;
} ]
}
在WarrantyResultCtrl
,您可以检查是否发生了错误并生成重定向。
编辑 :更清洁的解决方案:
// WarrantyCtrl
$scope.$on('$routeChangeError', function() {
// handle the error
});
$scope.submitWarranty = function() {
$scope.loading = true;
Warranty.setRequestData($scope.data);
$location.path('/warrantyResult');
};
( plunker演示 )
我发现如果Promise
被rejected
,控制器根本不会被触发,你的视图永远不会被呈现 - 和你一样。
我还发现,如果你在$routeProvider
的resolve
$routeProvider
.then()
处理Promise
, $routeProvider
.then()
将返回一个新的Promise
,它被resolved
,你的控制器$routeProvider
被解雇了,尽管没有数据你在期待。
例如:
$routeProvider.when('/warrantyResult', {
templateUrl : 'partials/warranty-result.html',
controller : 'WarrantyResultCtrl',
resolve : {
response : [ 'Warranty', function(Warranty) {
return Warranty.sendRequest()
.then(null, function(errorData) {
// Log an error here?
// Or do something with the error data?
});
}]
}
});
现在在您的控制器中,您将需要检查response
是否undefined
。 如果它undefined
那么您将知道对Warranty.sendRequest()
的调用失败,您可以采取相应的行动。
对于它的价值,我没有走这条路。 相反,我将$location
服务注入resolve
处理程序,并在$http
调用被拒绝时重定向到错误页面。
更新只是注意到在您的控制器中,您应该注入Warranty
服务,而应该注入您在resolve
定义的response
。 这将阻止您的视图呈现,直到从Warranty.sendRequest()
返回的Promise得到解决。
深入搜索后,我无法找到解决此问题的方法。
我决定在我的路由定义中删除解析参数,并在WarrantyCtrl中使用以下代码片段。
$scope.submitWarranty = function() {
$scope.formatUserData();
if ($scope.verifyUserData()) {
$scope.loading = true;
Warranty.setRequestData($scope.data);
Warranty.sendRequest().success(function() {
$location.path('/warrantyResult');
}).error(function() {
$location.path('/webserviceError');
});
}
};
不是很聪明,但是工作有意......如果有人仍然有原始问题的解决方案,我会很高兴看到它!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.