Friday 25 March 2016

angularjs - angular-ui-router: resolve on root state



As far as I understand ui.router




You have $stateProvider



in it you can write $stateProvider.state()



you can write



    .state('account', {
url: '/account',
template: ''

})
.state('account.register', {
url: '/register',
templateUrl: '/account/views/register.html',
data: { title: 'Create Account' },
controller: 'AccountRegister'
})


but 'account' is a child of some kind of root state.




So my thought is, the root state of ui.router has a , just like 'account' has the template '', so index.html would be the root state. Even 'home' with url: '/' would be or rather is a child of this root state.



and if I'm able to access the root state and say it should resolve a User service this resolved value should be available on all states (or better on every state that is a child of the root state, aka all). The User service promise makes a $http.get('/api/user/status') and it returns {"user":{id: "userid", role: "role"}} or {"user":null}
This would guarantee that the value returned by the User service is always populated.



How do I access the root state and say it should resolve e.g. User.get()?



Or let me rephrase that.




A user object should be available to all controllers.
The information about the currently logged in user is supplied by a $http.get('/api/user/status')
That's the problem and I'm looking for a DRY solution that, assuming the api is serving, is 100% safe to assume a user object is set, aka the promise is always fulfilled, aka "waiting for the promise to resolve before continuing".


Answer



Disclaimer — messing around with you root scope is not a good idea. If you're reading this, please note that the OP, @dalu, wound up canning this route and solved his issue with http interceptors. Still — it was pretty fun answering this question, so you might enjoy experimenting with this yourself:






It might be a little late, but here goes




As mentioned in the comments and from my experience so far, this is not possible to do with the ui-router's api (v0.2.13) seeing as they already declare the true root state, named "". Looks like there's been a pull request in for the past couple years about what you're looking for, but it doesn't look like it's going anywhere.



The root state's properties are as follows:



{
abstract: true,
name: "",
url: "^",
views: null
}



That said, if you want to extend the router to add this functionality, you can do this pretty easily by decorating the $stateProvider:



$provide.decorator('$state', function($delegate) {
$delegate.current.resolve = {
user: ['User', '$stateParams', httpRequest]
};
return $delegate
});



Note that there are two currents: $delegate.current - the raw "" state - and $delegate.$current - its wrapper.



I've found a bit of a snag, though, before this becomes the solution you were looking for. Every time you navigate to a new state, you'll make another request which has to be resolved before moving forward. This means that this solution isn't too much better than event handling on $stateChangeStart, or making some "top" state. I can think of three work-arounds off the top of my head:




  • First, cache your http call. Except I can see how this pretty much invalidates certain use-cases, perhaps you're doing something with sessions.

  • Next, use one of your singleton options (controller/service) to conditionally make the call (maybe on just set a flag for first load). Since the state is being torn down, it's controller might be as well - a service might be your only option.

  • Lastly, look into some other way of routing - I haven't used ui.router-extras too much, but sticky states or deep state redirect might do the trick.




I guess, lastly, I'm obligated to remind you to be careful with the fact that that you're working on the root-level. So, i mean, be about as careful as you should be when doing anything in root-level.



I hope this answers your question!


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...