18

I'm using Angular ui-router and have a resolve function set up for one of my states, before the controller is initialized. I retrieve some data, loop through and match it up the URL stateParam, and if a match is found, resolve the promise to the controller and return that object in the promise. That's all working well.

However, if a match isn't found I simply want to redirect to a different state by rejecting the promise and running $state.go('state');

Simply this:

deferred.reject();
$state.go('state',{params: 'param'});

But this doesn't seem to do anything. The controller just hangs, and I get no console errors or anything. Any ideas?

This question apply to verion 0.xx, many things have changed in version 1.xx

Phung D. An
  • 2,402
  • 1
  • 22
  • 23
Sean Thompson
  • 902
  • 1
  • 9
  • 19

2 Answers2

31

ui-router is supposed to throw a $stateChangeError if a route resolve is rejected. You need to watch for this event, and trigger your state transition there.

As per the wiki:

$stateChangeError - fired when an error occurs during transition. It's important to note that if you have any errors in your resolve functions (javascript errors, non-existent services, etc) they will not throw traditionally. You must listen for this $stateChangeError event to catch ALL errors.

https://github.com/angular-ui/ui-router/wiki#wiki-state-change-events


As @gustavohenke mentioned in the comments, a good place to put this handler is your app's primary .run() function.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
Matt Way
  • 32,319
  • 10
  • 79
  • 85
  • 2
    I've tried listening on the $stateChangeError event myself, and never see it triggered, even when I know $q.reject has been called. This leaves the app in the previous state, with no notification, or, in the case of a first load, in an unknown state. – weierophinney Apr 01 '14 at 20:57
  • 1
    You need to make sure you are handling `$stateChangeError` in a controller that has been loaded (eg. higher in the hierarchy than your resolve call). If you need to catch the root state, use an `ng-controller` on your html or body tag as a site wide always loaded controller. – Matt Way Apr 15 '14 at 11:29
  • 5
    @MattWay even better: use a run block, and listen in the `$rootScope`. – gustavohenke Dec 10 '14 at 18:47
  • 1
    https://ui-router.github.io/guide/ng1/migrate-to-1_0#state-change-events $stateChangeError deprecated, use transition hooks – Simon D Dec 01 '17 at 10:04
-3

You're misunderstanding how promises work. deferred.reject() simply notifies the deferred.promise that it has been rejected.

var promise = deferred.promise;

promise.then(
  function (result) { 
    // this function runs if the promise was resolved
  },
  function (result) {
    // this function runs if the promise was rejected
    // this is where you should put $state.go(..)
  }
)
Gabe
  • 2,117
  • 1
  • 16
  • 13