2015-11-29 7 views
9

角度アプリのグローバルエラーハンドラは$http interceptorと書かれていますが、それ以上のステップを進めたいと思います。私が望むのは、失敗した(拒否された)各呼び出しのためのもので、約束の消費者は最初にエラーを解決しようとするべきであり、まだ解決されていない(捕らえられていない)引き継ぐグローバルエラーハンドラ。「処理されていない」約束を捉えるだけのグローバルエラーハンドラ

使用する場合、私のグローバルエラーハンドラは、画面の上部に唸り「alert box」を表示します。しかし、私はいくつかのモーダルをポップアップしています。私はそこに明示的にエラーを処理し、モーダル自体にエラーメッセージを表示します。したがって、本質的に、このモーダルコントローラは、拒否された約束を「処理済み」とマークする必要があります。しかし、インターセプタは常に$http errorで最初に実行されるように見えるので、私はそれを行う方法を理解できません。ここで

は私のインターセプタコードです:

angular.module("globalErrors", ['angular-growl', 'ngAnimate']) 
    .factory("myHttpInterceptor", ['$q', '$log', '$location', '$rootScope', 'growl', 'growlMessages', 
     function ($q, $log, $location, $rootScope, growl, growlMessages) { 
      var numLoading = 0; 
      return { 
       request: function (config) { 
        if (config.showLoader !== false) { 
         numLoading++; 
         $rootScope.loading = true; 
        } 
        return config || $q.when(config) 
       }, 
       response: function (response) { 
        if (response.config.showLoader !== false) { 
         numLoading--; 
         $rootScope.loading = numLoading > 0; 
        } 
        if(growlMessages.getAllMessages().length) { // clear messages on next success XHR 
         growlMessages.destroyAllMessages(); 
        } 
        return response || $q.when(response); 
       }, 
       responseError: function (rejection) { 
        //$log.debug("error with status " + rejection.status + " and data: " + rejection.data['message']); 
        numLoading--; 
        $rootScope.loading = numLoading > 0; 
        switch (rejection.status) { 
         case 401: 
          document.location = "/auth/login"; 
          growl.error("You are not logged in!"); 
          break; 
         case 403: 
          growl.error("You don't have the right to do this: " + rejection.data); 
          break; 
         case 0: 
          growl.error("No connection, internet is down?"); 
          break; 
         default: 
          if(!rejection.handled) { 
           if (rejection.data && rejection.data['message']) { 
            var mes = rejection.data['message']; 
            if (rejection.data.errors) { 
             for (var k in rejection.data.errors) { 
              mes += "<br/>" + rejection.data.errors[k]; 
             } 
            } 
            growl.error("" + mes); 
           } else { 
            growl.error("There was an unknown error processing your request"); 
           } 
          } 
          break; 
        } 
        return $q.reject(rejection); 
       } 
      }; 
     }]).config(function ($provide, $httpProvider) { 
     return $httpProvider.interceptors.push('myHttpInterceptor'); 
    }) 

は、これは私がモーダル約束コールが見えるように期待するかの大まかなコードです:

$http.get('/some/url').then(function(c) { 
       $uibModalInstance.close(c); 
      }, function(resp) { 
       if(resp.data.errors) { 
        $scope.errors = resp.data.errors; 
        resp.handled = true; 
        return resp; 
       } 
      }); 
+0

があなたの代わりにサーバー側でそれを実装するので考えたことはありますか?あなたが*解決しようとしていると言うときにも、その例を挙げることができます。 – Rajesh

+0

サーバーでそれを行うことはできません、約束のクライアント側で作業することです。解決しようとすると、グローバルなエラーハンドラは、http約束のエラーの最後のcatchallでなければならないということです。現在、エラーが発生したときに最初に実行されます。 –

答えて

2

1.ソリューション(ハック方法)

これを行うには、サービスを作成します。約束は連鎖可能で、基本的にコントローラーレベルでプロパティhandledをマークするので、この約束をあなたのサービスに渡す必要があり、処理されないエラーを処理します。

myService.check(
    $http.get('url/to/the/endpoint') 
      .then(succCallback, errorCallback) 
); 

2.ソリューション(好ましい方法)

それとも、より良い解決策は、$ HTTPのラッパーを作成し、このような何かをすることです:

myhttp.get('url/to/the/endpoint', successCallback, failedCallback); 

function successCallback(){ ... } 
function failedCallback(resp){ 
    //optional solution, you can even say resp.handled = true 
    myhttp.setAsHandled(resp); 

    //do not forget to reject here, otherwise the chained promise will be recognised as a resolved promise. 
    $q.reject(resp); 
} 

ここmyhttpサービスを呼び出します与えられた成功と失敗したコールバックを適用して、自分の失敗したコールバックを連鎖させ、処理されたプロパティが真か偽かをチェックすることができます。

myhttpサービスの実装(更新は、単なるオプションですが、それは一つの場所ですべてを保持しますので、それは(属性が容易に変更し、一つの場所に「取り扱わ」)よりよいソリューションですsetAsHandled機能を追加しました:

function myhttp($http){ 
    var service = this; 

    service.setAsHandled = setAsHandled; 
    service.get = get; 

    function setAsHandled(resp){ 
     resp.handled = true; 
    } 

    function get(url, successHandler, failedHandler){ 
     $http.get(url) 
      .then(successHandler, failedHandler) 
      .then(null, function(resp){ 
        if(resp.handled !== true){ 
         //your awesome popup message triggers here. 
        } 
      }) 
    } 
} 
を同じことを達成するために必要な

3.ソリューション

#2と同じですが、以下のコード:

myhttp.get('url/to/the/endpoint', successCallback, failedCallback); 

function successCallback(){ ... } 
function failedCallback(resp){ 
    //if you provide a failedCallback, and you still want to have your popup, then you need your reject. 
    $q.reject(resp); 
} 

O THER例:

//since you didn't provide failed callback, it'll treat as a non-handled promise, and you'll have your popup. 
myhttp.get('url/to/the/endpoint', successCallback); 

function successCallback(){ ... } 

myhttpサービスの実装:

function myhttp($http){ 
    var service = this; 

    service.get = get; 

    function get(url, successHandler, failedHandler){ 
     $http.get(url) 
      .then(successHandler, failedHandler) 
      .then(null, function(){ 
       //your awesome popup message triggers here. 
      }) 
    } 
} 
+0

これは動作する可能性があります...私は '' '$ http''を使っているところで' '' $ q''の依存関係を取り除きたいと思うでしょう...おそらく '' setAsHandled''で却下するのは簡単でしょう'サービスメソッド。 –

+0

いいえ、失敗したハンドラであなたの約束を拒否する必要があるので、$ qが必要になります。さもなければ、あなたの 'get'サービス関数では、それの失敗のケースをキャッチしません。 – Iamisti

+0

そうですが、 '' '$ http''を使っているすべての場所に' '' $ q''を挿入したくないと言っています。 –

関連する問題