46

Update: this should be possible in angular-ui-router as of 1.0.0alpha0. See the release notes https://github.com/angular-ui/ui-router/releases/tag/1.0.0alpha0 and the issue https://github.com/angular-ui/ui-router/issues/1018 I created.

I would like to access the state's name and other attributes the app is navigating to using angular ui-router when working on the resolve.

The reason: I want load some user data (including their access rights) asynchronously before allowing the app the enter that page.

Currently this is not possible because injecting $state into the resolve points to the state you're navigating away form, not to the one you're navigating to.

I know I can:

  • get the toState somewhere else with $rootScope('$stateChangeStart') and save it in my settings service for instance. But I think it's a little messy.
  • hard code the state into the resolve, but I don't want to reuse my resolve for all pages

I also created an issue on the ui-router github (Please + 1 if you are interested!): https://github.com/angular-ui/ui-router/issues/1018

Here's my code so far. Any help appreciated!

.config(function($stateProvider) {

    $stateProvider.state('somePage', {
        // ..
        resolve: {
            userData: function($stateParams, $state, Settings) {
                return Settings.getUserData() // load user data asynchronously
                    .then(function (userData) {
                        console.log($stateParams);
                        console.log($state);
                        // Problem: $state still points to the state you're navigating away from
                    });
            }
        }
    });
});
3
  • I would be interested in an answer to this as well...facing the exact same situation. Commented Apr 14, 2014 at 20:57
  • This doc is pretty well explaining how to use resolve github.com/angular-ui/ui-router/wiki Commented Sep 6, 2014 at 22:02
  • Hi @Timmz thanks for your input. Unfortunately the documentation does not provide information on how to access the $state info you're navigating to. Injecting $state gives you the state you're navigating away form at the time of the resolve. Commented Sep 9, 2014 at 12:49

4 Answers 4

56

Update for Ui-Router 1.x

$provide.decorator('$state', ($delegate, $transitions) => {
    $transitions.onStart({}, (trans) => {
      $delegate.toParams = trans.params()
      $delegate.next = trans.to().name
    })
    return $delegate
  })

Ui-Router 0.x

You can always decorate $state with next and toParams properties:

angular.config(function($provide) {
  $provide.decorator('$state', function($delegate, $rootScope) {
    $rootScope.$on('$stateChangeStart', function(event, state, params) {
      $delegate.next = state;
      $delegate.toParams = params;
    });
    return $delegate;
  });
});

And use as such:

.state('myState', {
    url: '/something/{id}',
    resolve: {
        oneThing: function($state) {
            console.log($state.toParams, $state.next);
        }
    }
});
Sign up to request clarification or add additional context in comments.

Comments

31

So I discovered the answer to this myself. If you're code is behaving like mine, the $stateParams object is properly injected, but $state is an empty (or old) state object.

What worked for me was referencing this in the resolve function:

.state('myState', {
    url: '/something/{id}',
    templateUrl: '/myTemplate.html',
    controller: function() {},
    resolve: {
        oneThing: function($stateParams) {
            console.log($stateParams); // comes through fine
            var state = this;
            console.log(state); // will give you a "raw" state object
        }
    }
})

The first log will return what you'd expect. The second log will return a "raw" (for lack of a better term) state object. So, for instance, to get the state's name, you can access, this.self.name.

I realize this isn't preferred...it would be a lot nicer if $state (or another standardized object) could provide this information for us at the resolve, but this is the best I could find.

Hope that helps...

8 Comments

This seems to work pretty well, thanks! Do you have any documentation or proof that this is the intended behavior? I'm having some reservations about integrating this into my code, without guarantee that this won't break in future versions.
This approach seems to break when you include the resolve in an abstract (parent) state. You'd expect $state to be the extending state, however this returns the parent state instead. I don't know how to work around this (yet), or if this is possible at all. Nonetheless I figured I'd add my findings to this resolution :)
@NathanRutman thanks for adding your viewpoint. I understand what you're saying and fully agree. Having said that, having a means of knowing what the full state "path" is (even when in the parent state) could be very useful information; for example to access sub-state specific data. Anyway, it's an architectural decision that (as always) has it's pros and cons.
It doesn't work for me. 'this' inside resolve function is just window object.
@ThomasVervest, on a referencing (tho unrelated) topic, your comment gave me a realization that resolves do actually work in an abstract state. Earlier, I'd had issues and assumed we cannot, but turns out I was probably trying to use $stateParams / $state in my abstract route's resolves. +1 for the indirect #tapsTheHead
|
1

this.toString() will give you the state name

Comments

0

This has been asked here.

It looks like they built into 1.0.0-rc.2 $state$ which you can inject into the resolve function and get this information.

resolve: {
  oneThing: function($state$) {
    console.log($state$);
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.