首页 文章

AngularJS - 使用$ routeProvider:resolve拒绝$ http承诺

提问于
浏览
13

我试图在 $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并解决它,即使请求失败,但我想知道是否有更简单的解决方案 .

感谢阅读,并希望,帮助:)

3 回答

  • 0

    我认为从 resolve 执行此操作的唯一方法是手动解决 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 中,您可以检查是否发生了错误并生成重定向 .

    EDIT :更清洁的解决方案:

    // WarrantyCtrl
    $scope.$on('$routeChangeError', function() {
      // handle the error
    });
    $scope.submitWarranty = function() {
        $scope.loading = true;
        Warranty.setRequestData($scope.data);
        $location.path('/warrantyResult');
    };
    

    (plunker演示)

  • 3

    我发现如果 Promiserejected ,控制器根本不会被触发,并且您的视图永远不会被渲染 - 与您相同 .

    我还发现,如果你在 $routeProviderresolve 中使用 .then() 处理 Promise.then() 将返回一个新的 Promise ,即 resolved 并且你的控制器终究会被触发,尽管没有你期望的数据 .

    例如:

    $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() 的调用失败,您可以采取相应的行动 .

    对于它的 Value ,我没有走这条路 . 相反,我将 $location 服务注入 resolve 处理程序,并在 $http 调用被拒绝时重定向到错误页面 .

    UPDATE 刚刚注意到在你的控制器中注入 Warranty 服务时应该注入 resolve 中定义的 response . 这将阻止您的视图呈现,直到从 Warranty.sendRequest() 返回的Promise得到解决 .

  • 8

    深入搜索后,我无法找到解决此问题的方法 .

    我决定在我的路由定义中删除解析参数,并在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');
            });
        }
    };
    

    不是很聪明,但是工作有意......如果有人仍然有原始问题的解决方案,我会很高兴看到它!

相关问题