web-dev-qa-db-fra.com

Comment gérer une erreur dans la résolution angular-ui-router

J'utilise resolve du routeur angular-ui-router pour obtenir les données du serveur avant de passer à un état. Parfois, la demande au serveur échoue et je dois informer l'utilisateur de l'échec. Si j'appelle le serveur depuis le contrôleur, je peux mettre then et appeler mon service de notification en cas d'échec de l'appel. J'ai mis l'appel au serveur dans resolve parce que je veux que les états descendants attendent le résultat du serveur avant de démarrer.

Où puis-je intercepter l'erreur en cas d'échec de l'appel au serveur? (J'ai lu la documentation mais je ne sais toujours pas comment. De plus, je cherche une raison d'essayer ce nouvel outil d'extraits :).

"use strict";

angular.module('MyApp', ["ui.router"]).config([
  "$stateProvider",
  "$urlRouterProvider",
  function ($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("/item");
    $stateProvider
    .state("list", {
      url: "/item",
      template: '<div>{{listvm}}</div>' +
        '<a ui-sref="list.detail({id:8})">go to child state and trigger resolve</a>' +
        '<ui-view />',
      controller: ["$scope", "$state", function($scope, $state){
          $scope.listvm = { state: $state.current.name };
      }]
    })
    .state("list.detail", {
      url: "/{id}",
      template: '<div>{{detailvm}}</div>',
      resolve: {
        data: ["$q", "$timeout", function ($q, $timeout) {
          var deferred = $q.defer();
          $timeout(function () {
            //deferred.resolve("successful");
            deferred.reject("fail");   // resolve fails here
          }, 2000);
          return deferred.promise;
        }]
      },
      controller: ["$scope", "data", "$state", function ($scope, data, $state) {
        $scope.detailvm = {
          state: $state.current.name,
          data: data
        };
      }]
    });
  }
]);
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>

<div ng-app="MyApp">
  <ui-view />
</div>
43
Endy Tjahjono

Le problème est que si l'une des dépendances dans la résolution de l'itinéraire est rejetée , le contrôleur ( pas être instancié. Vous pouvez donc convertir l'échec en données que vous pouvez détecter dans le contrôleur instancié.

Exemple de pseudocode: -

   data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
      return $timeout(function () { //timeout already returns a promise
        //return "Yes";
        //return success of failure
         return success ? {status:true, data:data} : {status:false}; //return a status from here
       }, 2000);
     }]

et dans votre contrôleur: -

 controller: ["$scope", "data", "$state", function ($scope, data, $state) {
      //If it has failed
      if(!data.status){
        $scope.error = "Some error";
       return;
      }
        $scope.detailvm = {
          state: $state.current.name,
          data: data
        };

Si vous faites un $http appelez ou similaire, vous pouvez utiliser la promesse http pour résoudre les données toujours même en cas d'échec et renvoyer un état au contrôleur.

Exemple:-

resolve: {
        data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
           return $http.get("someurl")
             .then(function(){ return {status:true , data: "Yes"} }, 
                    function(){ return {status:false} }); //In case of failure catch it and return a valid data inorder for the controller to get instantated
        }]
      },
"use strict";

angular.module('MyApp', ["ui.router"]).config([
  "$stateProvider",
  "$urlRouterProvider",
  function ($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("/item");
    $stateProvider
    .state("list", {
      url: "/item",
      template: '<div>{{error}}</div><div>{{listvm}}</div>' +
        '<a ui-sref="list.detail({id:8})">go to child state and trigger resolve</a>' +
        '<ui-view />',
      controller: ["$scope", "$state", function($scope, $state){
       $scope.listvm = { state: $state.current.name };
      }]
    })
    .state("list.detail", {
      url: "/{id}",
      template: '<div>{{detailvm}}</div>',
      resolve: {
        data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
           return $http.get("/").then(function(){ return {status:true , data: "Yes"} }, function(){ return {status:false} })
        }]
      },
      controller: ["$scope", "data", "$state", function ($scope, data, $state) {
   
    
        $scope.detailvm = {
          state: $state.current.name,
          data: data.status ? data :"OOPS Error"
        };
        
      }]
    });
  }
]);
 <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
    <script data-require="angular-ui-router@*" data-semver="0.2.10" src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
  <div ng-app="MyApp">
      <ui-view></ui-view>
    </div>
22
PSL

Vieille question mais j'ai eu le même problème et suis tombé dessus dans la section FAQ de FAQ)

Si vous rencontrez des problèmes où une erreur triviale n'a pas été détectée parce qu'elle se produisait dans la fonction de résolution d'un état, il s'agit en fait du comportement prévu des promesses selon la spécification.

erreurs dans la résolution .

Ainsi, vous pouvez détecter toutes les erreurs de résolution dans la phase d'exécution de votre application, comme ceci

$rootScope.$on('$stateChangeError', 
function(event, toState, toParams, fromState, fromParams, error){ 
        // this is required if you want to prevent the $UrlRouter reverting the URL to the previous valid location
        event.preventDefault();
        ... 
})
77
koox00