2

I have such a simple scenario,

enter image description here

App starts from Main View (/main), then click top right button to Sub View (/sub).

During app launching app.run(), user's profile will be loaded into a service userService, once if user went to Sub View, this profile will be read from that service userService then display, here is the code,

app.run(function($http, $rootScope, userService){
   $http.get('/profile').then(function(result){
        userService.setProfile(result.data.profile);
   });
});

app.service('userService', function(){
    var user = {}

    this.setProfile(profile){
        user.profile = profile;
    };

    this.getProfile(){
       return user.profile;
    }
});

In Sub View, getProfile() was invoked to display the info.

It works if user start from Main View -> button -> Sub View, however, if user manually refreshed Sub View or just start from Sub View, getProfile() will get nothing to display,I know that's because before the promise of getting profile returned, Sub View had been proceed.

I don't like to read profile from Sub View directly and dynamically because I have other pages need profile info as well, so is there any workaround or better design? thanks.

6
  • 1
    You could resolve the profile before the subview is loaded: stackoverflow.com/questions/19937751/… Commented Sep 7, 2015 at 15:20
  • 1
    run won't wait for the request to complete ... use resolve in router as mentioned. Issue is really simple if using ui-router and parent states Commented Sep 7, 2015 at 15:31
  • @BroiSates @charlietfl I feel resolve is not that convenient, I have to config every router to inject the profile to its controllers Commented Sep 7, 2015 at 16:08
  • that's why using ui-router and parent states is so helpful, you only have one resolve at parent level Commented Sep 7, 2015 at 17:09
  • @charlietfl would preloading init data then manually angular bootstrap, in app run set up this userService is a good practise? Commented Sep 8, 2015 at 2:56

2 Answers 2

0

Instead of using app.run you should probably utilize your route provider for this. Whether you use ngRoute or ui-router they both have resolve functionality. Instead of getting your profile in app.run you should probably move that to userService as well.

app.service('userService', function(){
    var self = this;
    self.user = {};

    self.getProfile = function() {
        return self.user.profile;
    };

    self.init = function() {
        return $http.get('/profile').then(function(result){
            self.user.profile = result.data.profile;
        });
    };
});

Now that your service is more factory like, you can utilize the initialization of it in the route provider. I use ui-router but this can easily be applied to ngRoute as well.

I start by creating an abstract state that handles the resolve which I can than 'import' in whichever other states I need.

.state('init', {
    abstract: true,
    resolve: ['userService', function(userService) {
        return userService.init();
    }]
});

Now I just use it in other states and I can assure that the userService is initialized.

.state('subView', {
    parent: 'init',
    url: '/subView'
    //other state stuff like template, controller, etc
});
Sign up to request clarification or add additional context in comments.

2 Comments

Yeah, in fact I changed to a similar way base on the comments, now I'm thinking to preload init data then manually angular bootstrap, in app run I'll set up this userService, what do you think about this, which one is a better practise and y?
I think its just two ways of completing the same thing. I'm not an angular guru so I can't really say which one is better as to me both seem like a fine way to bootstrap data. Loading it in app.run is one and done while using the router method requires your to include it in each route so that does save you some code, however I like the ability to choose which routes I want it required in.
0

The way I've worked around that is add the relevant data to $window.sessionStorage, roughly like this (you'll need to make $window available):

app.service('userService', function(){
  var user = {}
    if ($window.sessionStorage.profile)
        this.user.profile = JSON.parse($window.sessionStorage.profile)

  this.setProfile(profile){
      user.profile = profile;
      this.$window.sessionStorage.profile = JSON.stringify(profile)
  };

  this.getProfile(){
     return user.profile;
  }
});

1 Comment

This will work it around, but, profile will become a 'public' variable, you can even modify from outside of userService, not good enough.

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.