Skip to content
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

event.preventDefault() on $stateChangeStart together with '$urlRouterProvider.when("/", "/home")' causes infinite digest loop #2098

Closed
maxkoretskyi opened this issue Jul 14, 2015 · 12 comments

Comments

@maxkoretskyi
Copy link

I want to redirect user to default mydomain.com/home url when she hits mydomain.com. So I have the following in my config:

$stateProvider.state({ name: 'home', url: '/home', controller: function() { }, templateUrl: 'home.html'});
$urlRouterProvider.when("/", "/home");

Also, in my module's run function I subscribe to the $stateChangeStart event and if a user hasn't yet been resolved from the server I prevent the event until the user is resolved:

$rootScope.$on('$stateChangeStart', function (event) {
    if (!Session.isUserResolved()) {
    event.preventDefault();
        Session.getResolutionPromise().then(function () {
            $urlRouter.sync();
        });
    }

The problem is that event.preventDefault(); used in such a way causes infinite digest loop. Unfortunately, I can't reproduce this issue inside plunker probably because of some URL inconsistencies but it's reproducable inside simple .html file - here is the gist with this file's content.

I've also done a bit of debugging myself. When $stateChangeStart is fired, the router is transitioning to the home state with the url mydomain.com/home. This url is already set in a browser by angular. Then if transition is prevented, ui-router sets the url back to the original "/" here:

update: function(read) {
        if (read) {
          location = $location.url();
          return;
        }
        if ($location.url() === location) return;

        $location.url(location);
        $location.replace();
      }

Then angular's this $rootScope.$watch(function $locationWatch() { watcher is fired which checks for location change var urlOrStateChanged = oldUrl !== newUrl and finds the change, because URLs don't match - oldUrl is domain.com/home and newUrl is domain.com/ (set by router). Since there's a change, angular fires $locationChangeSuccess event, which is picked up by ui-router. In turn, ui-router finds this rule .when("/", "/home") and changes state to home, but the event is prevented again and so the closed-loop is continuing with angular's watcher's being fired again.

@maxkoretskyi
Copy link
Author

I seem to have found possible solution to the problem, please validate:

$urlRouterProvider.when("/", ['auth.Session', function (Session) {
    if (Session.isUserResolved()) {
        return "/articles";
    } else {
        return false;
    }
}]);

@nazan
Copy link

nazan commented Jul 16, 2015

I get the same error. Please check this plunk.

http://plnkr.co/edit/6q2jrZO4G0DV1mtoislB

@maxkoretskyi
Copy link
Author

Yes, your problem comes from the same cause as mine, just that you use otherwise instead of when. I just added a check that if it's a redirect to otherwise's URL, do not prevent event. Let's wait for the developers to take a look at this issue.

@momoadeli
Copy link

+1...We hit this issue too---solved with (original solution by @frankwallis on issue #600 ):

$urlRouterProvider.otherwise( function($injector) {
var $state = $injector.get("$state");
$state.go('homepage');
});

@guilbep
Copy link

guilbep commented Aug 26, 2015

@megabyzus wowow.. It is also working for me
I went from

$urlRouterProvider.otherwise('/dashboard');

to

$urlRouterProvider.otherwise( function($injector) {
    var $state = $injector.get("$state");
    $state.go('app.dashboard');
  });

@boonep
Copy link

boonep commented Sep 3, 2015

So, to fix for $urlRouterProvider.when:

Change this:

$urlRouterProvider.when('/', '/dashboard/main');

To this:

$urlRouterProvider.when('/', function($injector, $location) {
   var $state = $injector.get("$state");
   $state.go('dashboard.main');
});

@eddiemonge
Copy link
Contributor

duplicate of #2238

@christopherthielen
Copy link
Contributor

christopherthielen added a commit that referenced this issue Jan 23, 2016
@nfantone
Copy link

As mentioned here, #1022 (comment), this is was not fixed on 0.2.16. So anyone still experiencing this, should apply this workaround.

@christopherthielen
Copy link
Contributor

@nfantoneif would you mind posting a plunker showing your scenario? I'd be happy to reopen this if I can be shown that it's still a problem.

@nfantone
Copy link

@christopherthielen Well... this is happening in a rather large project. Putting together a plunkr won't be as easy as copy and pasting. Let me see what I can do.

But the symptoms are exactly the same as everyone else have described. And the solution was also the same fix.

Also, it seems I'm not the only one experiencing this after the alleged fix.

ExpFront pushed a commit to ExpFront/ui-router that referenced this issue Jun 23, 2016
@rameshkumarv
Copy link

I'm also faced the same issue, in my case I have $urlRouterProvider.otherwise("/dashboard") in route and event.preventDefault() in $stateChangeError block. I tried with code mentioned by boonep, that's not solved my case. Problem with my code was I didn't added /* @ngInject */ in myfile.js since I'm using typescript.

Check the error parameter value to identify the exact cause.

$rootScope.$on("$stateChangeError", (event, toState, toParams, fromState, fromParams, error) => {
event.preventDefault();
$state.go("somestate");
})

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

No branches or pull requests

9 participants