3

I am trying to set up a resolve on a view to get some user information before the view gets rendered, because the data from the API will determine what view they user will see. I tried putting my service into the resolve, but $stateParams are not set when inside the service for some reason:

.state('order.sharepoint', {
    url: '/sharepoint',
    abstract: true,
    controller: 'SharePointController',
    resolve: {
        OrderResolve: function(Order, $stateParams){ // Here $stateParams
            return Order.fetch();                    //   is set correctly!
        }
    }
});

Order Service

 app.factory('Order', function ($q, API, $stateParams) { // HERE $stateParams 
                                                         // is empty for some reason

    var Order = null;
    var service = {};

    service.fetch = function () {
       /// Here is my API call and everything
    }
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Matt Hintzke
  • 7,744
  • 16
  • 55
  • 113
  • Why not pass `$stateParams` to `service.fetch` as an argument? – SteamDev Nov 14 '14 at 22:21
  • I ended up doing that, but I still would like to know why the the other way isn't working. DI should solve the problem of me having to pass it into the fetch() function. – Matt Hintzke Nov 14 '14 at 22:26
  • $stateParams is populated only when the correct url is hit. Can you try $state.params? – Ralph Nov 14 '14 at 22:31
  • it is also empty...it doesn't make sense because this state is the one with the serviceId in the url... and it can be access in the resolve, so why not in the service? – Matt Hintzke Nov 14 '14 at 22:57

1 Answers1

0

There is a plunker, which is realted to this question: Angular and UI-Router, how to set a dynamic templateUrl. There we can see how to work with $stateParams and factories.

In general, factory, is created once. It is a singleton. The resolve, is fired as many times, as the state is reached. (while the created factory is already created... its constructor won't be the best place for reuse/reset)

This would be some factory def:

.factory('GetName', ['$http', '$timeout',
    function($http, $timeout) {
      return {
        get : function(id) {
          // let's get data via $http
          return $http
            .get("dataFromServer.json")
            .then(function(response){

              // simplified converter
              // taking the $http result and 
              // by id gets the name
              var converter = response.data;
              var name = converter[id];

              return {templateName : name}; 
          });
        },
      };
    }
]);

As we can see, its constructor takes references to services, which could be used later, often, inside of a method. In this case: get(id)

And this is the standard call for it inside of the resolver - or even in the templateProvider as in this example.

  $stateProvider
    .state('parent.child', {
      url: '/child/:someSwitch',
      views: {
        "page": {
          templateProvider: function($http, $stateParams, GetName) {

            // async service to get template name from DB
            return GetName
                .get($stateParams.someSwitch)
                // now we have a name
                .then(function(obj){
                   return $http
                      // let's ask for a template
                      .get(obj.templateName)
                      .then(function(tpl){
                          // haleluja... return template
                          return tpl.data;
                   });      
                })

          }, 
          controller: 'viewCtrl',
        }
      }
    });

This example should show, that factory as a singleton, can use IoC to be injected with the dependent services/factories. State related stuff, which is changing (ie. is NOT a singleton) must be passed as factory method param... Check it here

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335