From e00aa695e41ddc5ebd5d2b226aa0917a751b11aa Mon Sep 17 00:00:00 2001 From: christopherthielen Date: Sat, 23 Jan 2016 17:44:07 -0600 Subject: [PATCH] fix($state): statechangeCancel: don't clobber url if a new transition has started Closes #2238 Closes #2229 Closes #2185 Closes #2236 Closes #2098 Closes #600 --- src/state.js | 3 ++- test/stateSpec.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/state.js b/src/state.js index c439b1cbf..3e1a4ab0f 100644 --- a/src/state.js +++ b/src/state.js @@ -1084,7 +1084,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { */ if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams, options).defaultPrevented) { $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams); - $urlRouter.update(); + //Don't update and resync url if there's been a new transition started. see issue #2238, #600 + if ($state.transition == null) $urlRouter.update(); return TransitionPrevented; } } diff --git a/test/stateSpec.js b/test/stateSpec.js index 43599dbff..8715c091d 100644 --- a/test/stateSpec.js +++ b/test/stateSpec.js @@ -1648,3 +1648,32 @@ describe('$stateParams', function () { expect($stateParams.foo).toBeUndefined(); })); }); + +// Test for #600, #2238, #2229 +describe('otherwise and state redirects', function() { + beforeEach(module(function ($stateProvider, $urlRouterProvider) { + $urlRouterProvider.otherwise('/home'); + $stateProvider + .state('home', { url: '/home', template: 'home' }) + .state('loginPage', { url: '/login', templateUrl: 'login.html' }); + })); + + beforeEach(inject(function ($rootScope, $state) { + + $rootScope.$on('$stateChangeStart', function (event, toState) { + if (toState.name !== "loginPage") { + event.preventDefault(); + $state.go('loginPage', { redirectUrl: toState.name }); + } + }); + })); + + iit("should not go into an infinite loop", inject(function($location, $rootScope, $state, $urlRouter, $httpBackend) { + $httpBackend.expectGET("login.html").respond("login page"); + $location.url("notmatched"); + $urlRouter.update(true); + expect(function() { $httpBackend.flush(); }).not.toThrow(); + expect(function() { $rootScope.$digest(); }).not.toThrow(); + expect($state.current.name).toBe("loginPage") + })); +});