ui-router: Throw Error when `resolve` does not find dependency to inject

Say I have a factory called Config and there is a state such as:

$stateProvider.state('app', {
  url: '/',
  templateUrl: 'views/main.html',
  controller: 'MainCtrl',
  resolve: {
    config: function(Config) {
      return Config.reloadConfig();
    }
  }
}):

The resolve function of course fails, but no Error is thrown! When the project is minified (which is the only case when you notice something is wrong) finding this error is a pain; I had to go by trial and error through a lot of files to notice this.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 46 (14 by maintainers)

Most upvoted comments

@nonplus 's workaround was still failing silently, so I simply did the right thing to do: explode at any error, no mercy.

(function (angular) {
    'use strict';

    angular
        .module('YOUR-MODULE-NAME')
        .run(throwErrors);

    throwErrors.$inject = ['$rootScope'];
    function throwErrors($rootScope) {
        $rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
            throw error;
        });
    }
})(window.angular);

A missing dependency in a state resolve definition is a programming mistake and the library should help us catch these. This is a different from a resolve that fails (returns a rejected promise) which is a run-time error.

I would expect these mistakes to be logged out of the box (and possibly add a config option to suppress this logging for hacks that prefer to ignore errors). For now, I’m forced to do the following in my apps:

$rootScope.$on( '$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {
    if (error.message.match(/\[\$injector:unpr\]/)) {
        // Log missing 'resolve' dependency
        // See: https://github.com/angular-ui/ui-router/issues/469
        console.error("Invalid resolve in state '" + toState.name + "' - " + error.message);
    }
});
var app = angular.module('myApp', []);

app.run(['$rootScope', function ($rootScope) {

    $rootScope.$on('$stateChangeError', function (event, toState, toParams, fromState, fromParams, error) {

        throw error;

    });

}]);

I don’t understand. Why does it “of course” fail? Because the code is minified and Config is renamed? Try listening for $stateChangeError, or using the error callback in the result of transitionTo().

I’ve published my workaround as https://github.com/nonplus/angular-ui-router-resolve-error.

Although I’d still prefer/expect this behavior to be built in…

Yes, 1.0 will have a default error handler.

It is a cardinal sin for a library to swallow user errors! Expecting the user to need to try {} catch or Promise.catch the error assumes the user knows that there is an error in the first place.