Skip to content

Error Cannot read property 'globals' of null #326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
geun opened this issue Aug 16, 2013 · 27 comments
Closed

Error Cannot read property 'globals' of null #326

geun opened this issue Aug 16, 2013 · 27 comments
Labels

Comments

@geun
Copy link

geun commented Aug 16, 2013

It happen sometime but I don't know why.

Do I need to check something?

@timkindberg
Copy link
Contributor

Have you checked the thingamajig?

@timkindberg
Copy link
Contributor

Just kidding, the problem is we need more context, your issue is immensely too vague. Can you create a plunkr that shows the error?

@kentcdodds
Copy link

I've started experiencing this issue. I've traced it down to this line

Preview:

// Update $location
var toNav = to.navigable;
if (options.location && toNav) {
  $location.url(toNav.url.format(toNav.locals.globals.$stateParams)); // <-- This line

  if (options.location === 'replace') {
    $location.replace();
  }
}

I'm not certain how the toNav object gets it's locals property, but in the console I confirmed that it is null.

This happened when I clicked on a ui-sref anchor tag. Wasn't happening before, but I recently overhauled my routes so it could be anything.

@kentcdodds
Copy link

Here's some additional context... My (relevant) routes look like this:

$stateProvider.
  state('root', {
    abstract: true,
    templateUrl: '/main/index.html',
    controller: 'SuperCtrl',
    url: '/',
    resolve: {
      isAuthenticated: function($q, $http) {
        var deferred = $q.defer();
        $http.get('/api/v1/auth/isAuthenticated').then(function(response) {
          deferred.resolve(response.data.isAuthenticated);
        }, deferred.reject);
        return deferred.promise;
      }
    }
  }).
  state('root.route', {
    url: '',
    onEnter: function($state, isAuthenticated) {
      console.log('route');
      if (isAuthenticated) {
        $state.go('root.auth');
      } else {
        $state.go('root.anon');
      }
    }
  }).
  state('root.anon', {
    url: '',
    templateUrl: '/main/anon/anon.html',
    controller: 'FrontPageCtrl',
    onEnter: function() {
      console.log('anon');
    },
    context: ''
  }).
  state('root.auth', {
    url: '',
    templateUrl: '/main/auth.html',
    controller: 'MainCtrl',
    context: '',
    resolve: {
      currentUser: resolveCurrentUserInfo.resolveUser,
      userBuckets: resolveCurrentUserInfo.resolveBuckets,
      userStreams: resolveCurrentUserInfo.resolveStreams
    },
    onEnter: function() {
      console.log('auth');
    }
  }).
// more routes

Then I click: <a ui-sref="root.route">

Would love a tip on how to accomplish what I'm trying to do in a better way :) (that being, show a login page root.anon if the server says the user is not authenticated, otherwise show the normal page root.auth)

@kentcdodds
Copy link

@timkindberg any thoughts on this? I'm still seeing it and I'm not sure why...

@timkindberg
Copy link
Contributor

root.route only has a url and onEnter, so maybe that has something to do with it.

@kentcdodds
Copy link

I decided to ditch root.route altogether. So I'm not seeing this problem anymore... Still not sure what caused it though.

@nateabele
Copy link
Contributor

You're welcome to post a Plunkr that reproduces the issue.

@jamesplease
Copy link

@nateabele, I was able to reproduce this, albeit in a different fashion, with Angular v1.2.22 and ui-router v0.2.10.

One) Create a state with an onExit function. Put whatever you want within that function. For instance,

.state('left.link1', {
  url: 'link1',
  onExit: function() {
    console.log('I will explode your router');
  }
})

Two) Create another state that redirects to a third state in the onEnter callback.

.state('right', {
  url: "/right",
  onEnter: ['$state', function($state) {
    $state.transitionTo('left');
  }]
});

This error message will be thrown.

The use-case for this is:

I have some data that I want to share between a parent state and its child states, which a service helps with. On exit I tear down that shared service. This works fine in the majority of apps.

However, my logout state is unique. It does some logging out things, then redirects you to the login. All of this happens in onEnter, so the combination of this + the onExit callback causes this error.

Am I doing something unusual here? Should I not be redirecting in onEnter?

To see this in action, check out this Plunkr.

Click "Link1" in the Left tab, then go to the Right tab.

Just a note: I didn't make the original Plunkr. I just googled 'ui-router plunkr' and modified the first one that came up.

💥

@jamesplease
Copy link

It might be something to do with this line setting the exiting state's locals to be null, then immediately trying to access them here.

If this is the case, then it seems like it's confusing the exiting state from the entering state, but I'm just hypothesizing here.

@dougalcorn
Copy link

I suspect any time you transition from a state that has an onExit to a state that has an onEnter, this bug shows up.

@jamesplease
Copy link

@dougalcorn, I modified the Plunkr to test your theory, and it doesn't seem to throw the error.

@dougalcorn
Copy link

OK, here's the problem. I have a state (app.state.with.exit) with an onExit. I transition out of that state into another state that has an (app.state.middle) onEnter. That state's onEnter in turn calls $state.go to another state (app.state.final). The first transition works fine. But when the onEnter is called, the second transition uses the same fromPath as the first transition. All of these path elements in fromPath have had their locals set to null. So when the app.state.with.exit is exited again, invoking the onExit blows up because the locals are now null.

It seems like I would have expected the second transition's fromPath to correspond to app.state.middle; but maybe the first transition doesn't fully finish.

@jamesplease
Copy link

Sounds to me like you've nailed it, @dougalcorn. Do you think you would you have time to look into patching up this section of the code to introduce a PR?

@dougalcorn
Copy link

I'm not sure what the right fix is. Can I just add an existential check for exiting.locals to the conditional on this line?

@jamesplease
Copy link

Hmmm, yeah, it's a tough one given my tenuous understanding of the router's internals. That solution seems like it would work, but it doesn't seem that elegant.

It'd be more robust if there were some way to take a different action if this situation is detected. Like "oh, okay, I'm being forwarded along and will never enter the state, so something else entirely needs to happen now instead of the code that explodes." But as to the specifics of how to implement this I admit that I'm unsure!

@RyanVice
Copy link

@dougalcorn and @jmeas I was having this issue and used @dougalcorn proposed fix above and it fixed the issue for me. Is this something that can be put into the code? I don't mind helping however. I've never been involved in open source so please excuse my ignorance to the process.

@RyanVice
Copy link

I looked at the code a little closer and it looks like it's processing a potential set of OnExit actions. I'm assuming it's doing this to support nested states. That makes @jmeas comment above seem like the correct approach. The behavior of what to do when a transition from an OnExit contains a transition would need to be defined. Things like what if there is more than one OnExit with a transition would need to be considered. What's the way forward on this? I'd like to help however.

@dougalcorn
Copy link

Yes, my fix proposed above doesn't really fix the problem. If there is a state transition during either onExit or onEnter the whole chain is screwed up. What should happen to any other onExit or onEnter calls is undefined, but at least the fromPath needs to be reset.

On Mon, Aug 25, 2014 at 7:41 AM, RyanVice [email protected]
wrote:

I looked at the code a little closer and it looks like it's processing a potential set of OnExit actions. I'm assuming it's doing this to support nested states. That makes @jmeas comment above seem like the correct approach. The behavior of what to do when a transition from an OnExit contains a transition would need to be defined. Things like what if there is more than one OnExit with a transition would need to be considered. What's the way forward on this? I'd like to help however.

Reply to this email directly or view it on GitHub:
#326 (comment)

@RyanVice
Copy link

For others dealing with this issue, I ended up using $location.path('\blah'); in my code and it worked. I also tested and verified that using this approach still aloud the target route to have an onEnter() fire.

@corps
Copy link

corps commented Dec 11, 2014

Another solution for anyone facing this issue: as silly as it seems, try adding a $timeout around your transition from onEnter, if possible. The bug seems to occur due to processing a new transition during onEnter, so the $timeout will allow the original transition to complete before starting a new one, fixing the problem for me.

@imeninnik
Copy link

Faced this issue, when a link that I click have href="#" , so change attribute to href="" hides the error

@mamartins
Copy link

I found this error using an OnEnter on a abstract state, no onExit or onEnter on the state I want to transition to

@codephobia
Copy link

I was also getting this issue in a redirect in an onEnter, and wrapping the $state.go in a $timeout seems to have done the trick, but it causes the initial state to flicker in before the state change. $location.path only seems to work with the $timeout as well resulting in the same issue. Anyone have an idea of how I might get the redirect without the flicker?

@mamartins
Copy link

I've also solved it with a timeout

@chaseoli
Copy link

chaseoli commented Sep 13, 2016

@codephobia The reason you're getting the flicker is because 'onEnter' and 'onExit' callbacks get called when a state becomes active and inactive respectively. When you use onEnter and in combination with the timeout ui-router it loads the current route then when your timeout completes your redirected with $state.go (or however your redirecting within the timeout). Instead try to do your redirect logic inside a 'resolve' (not onEnter). A resolve function will be run prior to the current route's controller and view loading, so if you do a $state.go from within a resolve function your flicker should go away.

@A-Allam
Copy link

A-Allam commented Dec 4, 2017

I face this issue while back from the browser window, and it's working fine from the app.
Is there any solutions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests