web-dev-qa-db-fra.com

Erreur de gestion dans la fonction de résolution des routeurs ui? (aka $ stateChangeError) Passer des données à l'état d'erreur?

Dans mon application Angular, je gère les routes/états via ui-router. Si tout fonctionne - c'est super. Mais qu'est-ce qu'un bon moyen de gérer les erreurs survenant à l'intérieur des fonctions resolve?

Ma solution actuelle: j'ai un état error dédié (similaire au 404.html Commun). Qui ressemble à ceci:

// inside config()
.state('error', {
  url: '/error',
  controller: 'ErrorCtrl',
  templateUrl: 'error.html' // displays an error message
})

Si une erreur se produit à l'intérieur de resolve, je l'attrape via la fonction $stateChangeError Diffusée dans m run:

angular.module('myModule').run(function($state) {
  $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
    event.preventDefault();
    $state.go('error');
  });
});

Cela fonctionne, mais Je veux changer mon message d'erreur dans mon 'error.html' En fonction de l'erreur. Je ne veux pas polluer le $rootScope Et je veux le faire de manière esk ui-router.

Ma solution actuelle utilise $stateParams Pour les données d'erreur dans mon état error, mais je dois utiliser les paramètres de requête JSONified pour cela et obtenir une URL très moche:

// inside config()
.state('error', {
  url: '/error?data&status&config', // accept these three params
  controller: 'ErrorCtrl',
  templateUrl: 'error.html' // displays an error message
})

angular.module('myModule').run(function($state) {
  $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
    event.preventDefault();
    $state.go('error', JSON.stringify(error)); // error has data, status and config properties
  });
});

Question Existe-t-il une manière différente de passer l'objet error à mon état error sans uglifier mon URL? (Remarque: mon objet error est complexe et pas seulement une simple chaîne.)

29
Pipo

Vous pouvez transmettre des données via un service auquel vous devez accéder dans votre contrôleur d'erreurs ou dans la méthode d'état d'erreur onEnter.

Ou vous pouvez "enrichir" votre état d'erreur. Peut-être que ce n'est PAS la manière angular, mais ce que je veux dire est:

$rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
  event.preventDefault();
  $state.get('error').error = { code: 123, description: 'Exception stack trace' }
  return $state.go('error');
});

Et dans votre configuration d'état d'erreur:

.state('error', {
    url: 'error',
    resolve: {
        errorObj: [function () {
            return this.self.error;
        }]
    },
    controller: 'ErrorCtrl',
    templateUrl: 'error.html' // displays an error message
});

J'espère que cela t'aides

25
wilver

Une stratégie qui a fonctionné pour moi est que les fonctions resolve renvoient une promesse rejetée avec objet d'erreur:

$stateProvider.state('needs_authentication', {
    url: '/auth',
    resolve: {
        user: function ($q, authService) {
            if (authService.isAuthenticated()) {
                ...
            }
            else {
                var errorObject = { code: 'NOT_AUTHENTICATED' };
                return $q.reject(errorObject);
            }
        }
    }
});

Cela permet à votre $stateChangeError la fonction peut gérer des conditions d'erreur spécifiques:

$rootScope.$on('$stateChangeError', function (evt, toState, toParams, fromState, fromParams, error) {
    if (angular.isObject(error) && angular.isString(error.code)) {
        switch (error.code) {
            case 'NOT_AUTHENTICATED':
                // go to the login page
                $state.go('login');
                break;
            default:
                // set the error object on the error state and go there
                $state.get('error').error = error;
                $state.go('error');
        }
    }
    else {
        // unexpected error
        $state.go('error');
    }
});
25
Miller

Vous pouvez supprimer toute l'option url: et la remplacer par juste une option params :.

                .state('error', {
                    abstract: false,
                    templateUrl: templateFor('error'),
                    controller: controllerFor('error'),
                    params: { 'error': 'An error has occurred' },
                    resolve: {
                        error: [
                            '$stateParams', function ($stateParams) {
                                return  $stateParams.error;
                            }
                        ]
                    }
                })

Maintenant, il n'y a pas d'URL laide. et le contrôleur peut obtenir l'erreur en tant que paramètre.

4
Peter Marshall