Angular ui-router resolve value as string

allenhwkim picture allenhwkim · Jun 12, 2015 · Viewed 7k times · Source

With ui-router, I add all resolve logic in state function like this;

    //my-ctrl.js
    var MyCtrl = function($scope, customers) {
      $scope.customers = customers;
    }

    //routing.js
    $stateProvider.state('customers.show', {
      url: '/customers/:id',
      template: template,
      controller: 'MyCtrl',
      resolve: {   // <-- I feel this must define as like controller
        customers: function(Customer, $stateParams) {
          return Customer.get($stateParams.id);
        }
      }
    });

However IMO, resolve object must belong to a controller, and it's easy to read and maintain if it is defined within a controller file.

    //my-ctrl.js
    var MyCtrl = function($scope, customers) {
      $scope.customers = customers;
    }
    MyCtrl.resolve = {
      customers: function(Customer, $stateParams) {
        return Customer.get($stateParams.id);
      };
    };

    //routing.js
    $stateProvider.state('customers.show', {
      url: '/customers/:id',
      template: template,
      controller: 'MyCtrl',
      resolve: 'MyCtrl.resolve'   //<--- Error: 'invocables' must be an object.
    });

However, When I define it as MyCtrl.resolve, because of IIFE, I get the following error.

Failed to instantiate module due to: ReferenceError: MyCtrl is not defined

When I define that one as string 'MyCtrl.resolve', I get this

Error: 'invocables' must be an object.

I see that controller is defined as string, so I think it's also possible to provide the value as string by using a decorator or something.

Has anyone done this approach? So that I can keep my routings.js clean and putting relevant info. in a relevant file?

Answer

Jeff Fairley picture Jeff Fairley · Jun 12, 2015

It sounds like a neat way to build the resolve, but I just don't think you can do it.

Aside from the fact that "resolve" requires an object, it is defined in a phase where all you have available are providers. At this time, the controller doesn't even exist yet.

Even worse, though, the "resolve" is meant to define inputs to the controller, itself. To define the resolve in the controller, then expect it to be evaluated before the controller is created is a circular dependency.

In the past, I have defined resolve functions outside of the $stateProvider definition, at least allowing them to be reused. I never tried to get any fancier than that.

var customerResolve = ['Customer', '$stateParams',
    function(Customer, $stateParams) {
        return Customer.get($stateParams.id);
    }
];

// ....

$stateProvider.state('customers.show', {
  url: '/customers/:id',
  template: template,
  controller: 'MyCtrl',
  resolve: {
    customers: customerResolve
  }
});