Andrew Kim
Andrew Kim

Reputation: 3335

way to abstract an angular ui router state with resolve into a constructor function

I have this constructor function:

function State(url, templateUrl, controller, controllerAs, factory, resolveProp){
  this.url = url
  this.templateUrl = templateUrl
  this.controller = controller
  this.controllerAs = controllerAs
}

and in my router callback I have this:

$stateProvider
  .state('archetypes', new State('/admin/archetypes', './resources/features/admin/archetypes/index.html', 'archetypes', 'aaVM'))

This works fine. I have another route, however, that contains a resolve to get some back end data.

I thought I might be able to do something like this for my constructor:

function State(url, templateUrl, controller, controllerAs, factory, resolveProp){
  this.url = url
  this.templateUrl = templateUrl
  this.controller = controller
  this.controllerAs = controllerAs
  if(factory){
    this.resolve = {}
    this.resolve[resolveProp] = function(factory){
      return factory.getAll()
    }
  }
}

and then instantiate a state in this way:

.state(
    'archetypes',
     new State(
         '/admin/archetypes',
         './resources/features/admin/archetypes/index.html', 
         'archetypes',
         'aaVM',
         ArchetypesFactory,
         'archetypes'
     )
)

But I think the .state method calls the controller in order to process the resolve object, such that when I try the above state instantiation, it errors out because ArchetypesFactory is clearly undefined.

Note that when i write my state in this way:

.state('archetypes', {
  url: '/admin/archetypes',
  templateUrl: './resources/features/admin/archetypes/index.html',
  controller: 'archetypes',
  controllerAs: 'aaVM',
  resolve: {
    archetypes: function(ArchetypesFactory){
      return archetypesFactory.getAll()
    }
  }
})

It works fine.

Is there any way I can abstract the state configuration object with a resolve into a constructor function or ES6 class?

Upvotes: 0

Views: 70

Answers (1)

georgeawg
georgeawg

Reputation: 48968

The resolver function is invoked by the AngularJS injector. The injector needs an explicit form of annotation. One way is to use Inline Array Annotation:

function State(url, templateUrl, controller, controllerAs, factory, resolveProp){
  this.url = url;
  this.templateUrl = templateUrl;
  this.controller = controller;
  this.controllerAs = controllerAs;
  if(factory){
    this.resolve = {}
    this.resolve[resolveProp] = [factory, function(factory){
      return factory.getAll();
    }];
  };
}

Then specify a string for the factory parameter:

.state(
    'archetypes',
     new State(
         '/admin/archetypes',
         './resources/features/admin/archetypes/index.html', 
         'archetypes',
         'aaVM',
         //ArchetypesFactory,
         //USE string
         'ArchetypesFactory',
         'archetypes'
     )
)

Inline Array Annotation is the preferred way to annotate application components. When using this type of annotation, take care to keep the annotation array in sync with the parameters in the function declaration.

Upvotes: 1

Related Questions