2

I am building routes/states and the menu based on what the user is authorized to see. I've looked around and tried a few different things, but i'm hitting a brick wall. The SessionService object in the RoleService Factory is empty whenever RoleService.validateRole() is called. No route is added and the app is effectively dead. Why is the injected factory empty and the methods undefined.

Here is a simplified layout of the app starting in order of dependencies.

In app.run(), I am adding the states to the app instead of doing it in the config.

$stateProviderRef.state(value.stateName, state);

The states come from (a factory) AppConfig.getStates(), which returns an array.

var states = AppConfig.getStates();

In getStates() we validate each route's role.

if(RoleService.validateRole(routes[i].role))

The RoleService depends on the SessionService and the validateRole function does this check:

if(SessionService.currentUser.role === role)

The SessionService depends on the AuthenticationService which is just a factory that returns a promise using $http (the user object). The SessionService.currentUser is a function that .then()s the returned promise from the AuthenticationService.

 return {
     currentUser: function(){
         AuthenticationService.then(function(result){
             return result;
         });
     }
 };

I'm not sure of a better way to explain the code without including the entire files.

6
  • Check this stackoverflow.com/a/29013914/1679310 Commented Dec 1, 2015 at 8:57
  • What’s your version of AngularJS? Commented Dec 1, 2015 at 8:59
  • @RadimKöhler, Hi! I followed that actually. The setup is the same.. well except for the part that doesn't work. It seems like the factory isn't instantiated fast enough to not be null during app.run(). Commented Dec 1, 2015 at 15:51
  • @AntonStrogonoff, 1.4.7 Commented Dec 1, 2015 at 15:52
  • @schumacherj, in case you can create "broken" plunker I can assist. Without that, I can just add a note - it should work and in run all the services will be properly set up. Commented Dec 1, 2015 at 16:24

1 Answer 1

1

Based on the plunker (mentioned in comment), I updated/cloned it to another, which is working

I. simple - when static data are returned (no $http)

Because the service SessonService was defined like this:

return {
    currentUser: function() {
    ...

we cannot call it as a property:

...
return {
    validateRoleAdmin: function () {
        if (SessionService.currentUser.role === 'admin') {
        ...
    },

    validateRole: function (role) {
        if(SessionService.currentUser.role === role){
        ...

it is a function it must be called as a function currentUser():

return {
    validateRoleAdmin: function () {
        if (SessionService.currentUser().role === 'admin') {
        ...
    },

    validateRole: function (role) {
        if(SessionService.currentUser().role === role){
        ...

II. waiting for async calls

The adjusted example

Next, if we in example create a static result of the service AuthenticationService:

angular.module('daedalus').factory('AuthenticationService', 
    function() {
      return {"idsid": "ad_jdschuma","role": "user","id": "33333"}
    }
)

we cannot expect there will be some then method:

currentUser: function() {
  //AuthenticationService.then(function(result) {
  //  return result;
  //});
  return AuthenticationService;
}

And to make it really async we can replace it with this:

angular.module('daedalus').factory('AuthenticationService', 
    ['$timeout', function($timeout) {

    return {
      getData: function() {
        return $timeout(function() {
          return {
            "idsid": "ad_jdschuma",
            "role": "user",
            "id": "33333"
          }
        })
      }
    };     
 }])

And then use even the .then() - Session service:

angular.module('daedalus').factory('SessionService', ['AuthenticationService', 
    function(AuthenticationService) {

        return {
              currentUser: function(){
                    return AuthenticationService
                      .getData()
                        .then(function(result){
                                return result;
                            });
                        }
        };
  }]
)

And the RoleService:

  return {
    ...
    validateRole: function(route) {
      console.log('SessionService currentUser: ' + JSON.stringify(SessionService))
      return SessionService
        .currentUser()
        .then(function(userRole) {
          if (userRole.role === route.role) {
            return route;
          } else {
            return null;
          }
        })
    }

And with this in place in appConfig

getStates: function(){
    var items = [];
    var deffered = $q.defer();
    var validatedCount = routes.length;
    for(var i=0,len=routes.length; i<len; i++){
      var route = routes[i];
      RoleService
        .validateRole(route) 
        .then(function(route){
            if(route) {
                 items.push(route.stateConfig)
          }
          if(--validatedCount === 0 ){ // all processed
           deffered.resolve(items)
          }
        })
    }
    return deffered.promise;
}

We can do that in run:

AppConfig
  .getStates()
  .then(function(states) {console.log(states)
    angular.forEach(states, function(value, key) {
      var state = {
        "url": value.url,
        "templateUrl": value.templateUrl,
        "controller": value.controller
      };
      $stateProviderRef.state(value.stateName, state);


    });
    // Configures $urlRouter's listener *after* your custom listener            
    $urlRouter.sync();
  });

$urlRouter.listen();

Check it here

The concept of the second solution (async) is too .thenified(). I just intended to show that all is working. Better approach how to get security data is completely covered here:

Confusing $locationChangeSuccess and $stateChangeStart

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.