Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise dependency resolution order in angular ui-router

Tags:

I have set up a top-level controller that is instantiated only when a promise (returned by a Config factory) is successfully resolved. That promise basically downloads the Web app configuration, with RESTful endpoints and so on.

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

This setup allows me to kind-of assert that the configuration is properly loaded before any lower controller gets a chance to use it.

Now I need to inject, in a deeper nested controller, another factory that uses Config and only works when it is resolved (look at it like a $resource wrapper that needs some Web service URLs). If I do:

$stateProvider
  .state('app.bottom.page', {
    url: '/bottom/page',
    templateUrl: 'views/_a_view.html',
    controller: 'BottomLevelCtrl',
    resolve: {
      TheResource: 'MyConfigDependingResource'
    }
  });

it looks like the resolve evaluation order does not follow the controller hierarchy from top to bottom, but from bottom to top, therefore:

  1. app.bottom.page is entered
  2. ui-router attempts to resolve MyConfigDependingResource, but the injection fails, because Config has never been initialized
  3. The ui-router resolution stops because of an error (without even throwing Errors, but that's another issue), and Config is never initialized by the top level controller

Why is ui-router resolving dependencies in a reverse order? How can I easily resolve my TheResource object after the top level MainCtrl has resolved Config (without relying on $inject, of course)?

UPDATE: from this plnkr's log you can see that the top level resolve is attempted only after the nested controller has started its own resolving process.

like image 761
frapontillo Avatar asked Feb 24 '14 09:02

frapontillo


Video Answer


1 Answers

Similarly to @Kasper Lewau's answer, one may specify a dependency on resolves withing a single state. If one of your resolves depends on one or more resolve properties from the same resolve block. In my case checkS relies on two other resolves

.state('stateofstate', {
    url: "/anrapasd",
    templateUrl: "views/anrapasd.html",
    controller: 'SteofsteCtrl',
    resolve: {
        currU: function(gamMag) {
            return gamMag.checkWifi("jabadabadu")
        },
        userC: function(gamUser, $stateParams) {
            return gamUser.getBipi("oink")
        },
        checkS: ['currU', 'userC', 'gamMag', function(currU, userC, gamMag) {
            return gamMag.check(currU, userC);
        }]
    }
})

**PS: **Check the "Resolves" section of the following document for more details about the inner-workings of resolve.

like image 180
Nikolay Melnikov Avatar answered Oct 14 '22 08:10

Nikolay Melnikov