UI-Router's resolve functions are only called once

All we need is an easy explanation of the problem, so here it is.

I was going to use ui-routers resolve feature to inject some readiliy resolved promises into my controllers.

I used the example plnkr to make an example.
Consider these nested states: route1 and route1.list.
I have a resolve function called abc defined on route1. Now when I navigate to route1 for the first time, abc is called and will be resolved. Now when I navigate to route1.list and back to route1, abc is not called again.

http://plnkr.co/edit/mi5H5HKVAO3J6PCfKSW3?p=preview

I guess this is intentional, but consider this use-case:
the resolve function retrieves some data via http and should be refreshed/invalidated at some point, maybe on every state change. Is there some way to do this when using nested states?
If the resolve function was called on every inject I could implement it any way I want: Return the old, resolved promise or create a new one.

I have only briefly tested this, but if the states were not nested things would work as I expected. Giving up on nested states because of this stinks though. And having the resolve dependencies available in nested states is actually nice.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Supplying the option reload:true to go() / transtionTo() / ui-sref does the trick 🙂
Thanks to Designing the Code for pointing me in this direction. The solution is a bit different though, so I write up this answer.

Reload is documented as follows:

reload (v0.2.5) – {boolean=false}, If true will force transition even if the state or params have not changed, aka a reload of the same state. It differs from reloadOnSearch because you’d use this when you want to force a reload when everything is the same, including search params.

The direct way is to change every ui-sref link into something like this: <a ui-sref="route1" ui-sref-opts="{reload: true}">.

To avoid supplying the option at every link I wrote a decorator around $state (see also http://plnkr.co/edit/mi5H5HKVAO3J6PCfKSW3?p=preview):

 myapp.config(function($provide) {
  $provide.decorator('$state', function($delegate) {
    var originalTransitionTo = $delegate.transitionTo;
    $delegate.transitionTo = function(to, toParams, options) {
      return originalTransitionTo(to, toParams, angular.extend({
        reload: true
      }, options));
    };
    return $delegate;
  });
});

Method 2

Try $state.reload();

It will force resolve the resolves again. Though think there is some issue related to this where controllers aren’t reloaded. (ui.router n00b here as well)

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply