angular-ui / ui-router

The de-facto solution to flexible routing with nested views in AngularJS
http://ui-router.github.io/
MIT License
13.53k stars 3k forks source link

Calling transitionTo in state's onEnter function #516

Closed Ryaan closed 11 years ago

Ryaan commented 11 years ago

$state.transitionTo doesn't appear to have any effect when called in the onEnter function when configuring states, neither does it appear to have any effect when called after a $stateChangeStart

Plunker example - http://plnkr.co/edit/02DgxY383LDnxwn4lqbE?p=preview

Stackoverflow post - http://plnkr.co/edit/02DgxY383LDnxwn4lqbE?p=preview

Ryaan commented 11 years ago
    if ($state.transition !== transition) return TransitionSuperseded;

does not seem to be working and I have no idea why.

danielgatis commented 11 years ago

I have the same problem when the user is not allowed to go to the state so I need to redirect to 403 state. The $state.go inside onEnter callback doesnt work.

"use strict"

@App.config ($stateProvider) ->

  $stateProvider
    .state "tasks/edit",
      url: "^/tasks/{id:[0-9]+}/edit"
      controller: "EditTaskCtrl"
      templateUrl: "angularjs/app/tasks/edit/edit"
      resolve:
        task: ($stateParams, Task) -> Task.get $stateParams.id
      onEnter: ($state, task) ->
        if not task.permissions.canUpdate
          $state.go '403', null,
            location: false

But the same code inside a $timeout works.

"use strict"

@App.config ($stateProvider) ->

  $stateProvider.state "tasks/edit",
    url: "^/tasks/{id:[0-9]+}/edit"
    controller: "EditTaskCtrl"
    templateUrl: "angularjs/app/tasks/edit/edit"
    resolve:
      task: ($stateParams, Task) -> Task.get $stateParams.id
    onEnter: ($timeout, $state, task) ->
      if not task.permissions.canUpdate
        $timeout ->
          $state.go '403', null,
            location: false
        , 0
timkindberg commented 11 years ago

Hell yeah @nateabele :+1:

jpodpro commented 8 years ago

can someone explain how this is supposed to work? using $state.go to a child state in the onEnter of the parent state i get a circular loop as the parent onEnter is always fired. according to @nateabele (http://stackoverflow.com/questions/19429652/ui-router-conditional-ui-views) this is how it is supposed to be done.

$stateProvider
        .state( 'homePage', {
            url: '/',
            onEnter: ['userService', '$state', function( userService, $state, title )
            {
                $state.go( 'homePage.guest' );
            }]
        })
        .state( 'homePage.user', {
            templateUrl: 'app/homePage/homePage.user.html',
            controller: 'HomeControllerUser',
            controllerAs: 'hcu'
        })
        .state( 'homePage.guest', {
            templateUrl: 'app/homePage/homePage.guest.html',
            controller: 'HomeControllerGuest',
            controllerAs: 'hcg'
        });
nateabele commented 8 years ago

@jpodpro I don't recall what my final suggestion was for the initial issue, but in 1.0 you can handle this simply by injecting $transition$ into your callbacks.

jpodpro commented 8 years ago

@nateabele i just updated to 1.0 only to discover there are virtually no examples for how to use the new system. your sample app: http://christopherthielen.github.io/new-state-vis gets a 404. i'm reading the documentation carefully but without examples it's not easy to understand how to migrate from events to hooks.

nateabele commented 8 years ago

I gave a talk with some examples: http://radify.io/talks/2015-sep-ngpittsburgh/

christopherthielen commented 8 years ago

I am in process of moving the example app to its new home. Sorry about that.

https://github.com/ui-router/sample-app

skeymeulen commented 8 years ago

@jpodpro Were you able to resolve this problem? I'm having exactly the same issue. I tried using $transition$, but previous() is always undefined.

nateabele commented 8 years ago

@skeymeulen It should never be undefined. See here: https://github.com/angular-ui/ui-router/blob/3d3c50fd7282ae386152b0e77f0795f424eafb8b/src/transition/transition.ts#L214

To take advantage of that, you need to be using redirect() in your hooks though, not $state.go().

christopherthielen commented 8 years ago

To take advantage of that, you need to be using redirect()

Return a TargetState from a hook, in order to redirect. Use the $state.target() factory method. (the docs currently incorrectly say .targetState())

skeymeulen commented 8 years ago

Thanks guys, $state.target was the was they key element for me. I was able to resolve the problem by returning $state.target() in $transitionsProvider. This eliminated the problem of the circular loop entirely. Didn't even need to use $transition$.

yesnoj commented 8 years ago

sorry for noob question but i still have problem with this onEnter and inner $state.go ...how can i solve?

gabycperezdias commented 8 years ago

Hi, I'm having some issues about this question...

I really don't understand the $state.target() mainly because inside my $stateProvider my $state is always undefined... so I can't use something like that... and the $transition$, what is that about?

Thanks

gabycperezdias commented 8 years ago

@skeymeulen Do you remember how did you solve that?

skeymeulen commented 8 years ago

@gabycperezdias I ended up not using $stateProvider, but the newer $transitionsProvider, which is based on transitions between states. Here is a (simplified) example of what I did:

  $transitionsProvider.onFinish({
    to: "main.dashboard"
  }, function ($state) {
      return $state.target('main.dashboard.user', {});
    }
  });

Documentation about possible hooks and examples can be found here.

As long as your not trying to redirect to a child state, $state.target should work just fine in onEnter, like this:

    $stateProvider.state('main.dashboard', {
      url: '/dashboard',
      onEnter: function($state){
        return $state.target("someStateThatIsNotAChildOfThisState", {});
      }
    })

I hope this can help, maybe you could clarify your specific case?

gabycperezdias commented 8 years ago

@skeymeulen my case is similar to this:

$stateProvider.state('logged', {
      url: '/logged',
      onEnter: function(){
        //REDIRECT to search_page
      }
    }).state('logged.search_page', {
      url: '/search_page'
    })

I am currently using $window.location = in the redirect part because my $stateis always undefined no matter if I am passing it as an argument to onEnter function, so, I think it won't be possible for me to use $state.target, and I don't know why this variable is always undefined :/