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 current
s: $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