Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ba391d2

Browse files
fix($location): do not get caught in infinite digest in IE9
Closes #11439 Closes #11935
1 parent 1105513 commit ba391d2

File tree

2 files changed

+216
-1
lines changed

2 files changed

+216
-1
lines changed

src/ng/browser.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ function Browser(window, document, $log, $sniffer) {
147147
// Do the assignment again so that those two variables are referentially identical.
148148
lastHistoryState = cachedState;
149149
} else {
150-
if (!sameBase) {
150+
if (!sameBase || reloadLocation) {
151151
reloadLocation = url;
152152
}
153153
if (replace) {

test/ng/locationSpec.js

+215
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,22 @@ describe('$location', function() {
663663
});
664664
});
665665

666+
667+
it('should not get caught in infinite digest when replacing path in locationChangeSuccess handler', function() {
668+
initService({html5Mode:true,supportHistory:false});
669+
mockUpBrowser({initialUrl:'http://server/base/home', baseHref:'/base/'});
670+
inject(
671+
function($browser, $location, $rootScope, $window) {
672+
$rootScope.$on('$locationChangeSuccess', function() {
673+
if ($location.path() !== '/') {
674+
$location.path('/').replace();
675+
}
676+
});
677+
$rootScope.$digest();
678+
}
679+
);
680+
});
681+
666682
it('should not infinitely digest when using a semicolon in initial path', function() {
667683
initService({html5Mode:true,supportHistory:true});
668684
mockUpBrowser({initialUrl:'http://localhost:9876/;jsessionid=foo', baseHref:'/'});
@@ -672,6 +688,162 @@ describe('$location', function() {
672688
}).not.toThrow();
673689
});
674690
});
691+
692+
693+
function updatePathOnLocationChangeSuccessTo(newPath) {
694+
inject(function($rootScope, $location) {
695+
$rootScope.$on('$locationChangeSuccess', function(event, newUrl, oldUrl) {
696+
$location.path(newPath);
697+
});
698+
});
699+
}
700+
701+
702+
describe('location watch for hashbang browsers', function() {
703+
704+
it('should not infinite $digest when going to base URL without trailing slash when $locationChangeSuccess watcher changes path to /Home', function() {
705+
initService({html5Mode: true, supportHistory: false});
706+
mockUpBrowser({initialUrl:'http://server/app/', baseHref:'/app/'});
707+
inject(function($rootScope, $location, $browser) {
708+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
709+
710+
updatePathOnLocationChangeSuccessTo('/Home');
711+
712+
$rootScope.$digest();
713+
714+
expect($browser.url()).toEqual('http://server/app/#/Home');
715+
expect($location.path()).toEqual('/Home');
716+
expect($browserUrl.calls.length).toEqual(1);
717+
});
718+
});
719+
720+
it('should not infinite $digest when going to base URL without trailing slash when $locationChangeSuccess watcher changes path to /', function() {
721+
initService({html5Mode: true, supportHistory: false});
722+
mockUpBrowser({initialUrl:'http://server/app/Home', baseHref:'/app/'});
723+
inject(function($rootScope, $location, $browser, $window) {
724+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
725+
726+
updatePathOnLocationChangeSuccessTo('/');
727+
728+
$rootScope.$digest();
729+
730+
expect($browser.url()).toEqual('http://server/app/#/');
731+
expect($location.path()).toEqual('/');
732+
expect($browserUrl.calls.length).toEqual(1);
733+
expect($browserUrl.calls[0].args).toEqual(['http://server/app/#/', false, null]);
734+
});
735+
});
736+
737+
it('should not infinite $digest when going to base URL with trailing slash when $locationChangeSuccess watcher changes path to /Home', function() {
738+
initService({html5Mode: true, supportHistory: false});
739+
mockUpBrowser({initialUrl:'http://server/app/', baseHref:'/app/'});
740+
inject(function($rootScope, $location, $browser) {
741+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
742+
743+
updatePathOnLocationChangeSuccessTo('/Home');
744+
$rootScope.$digest();
745+
746+
expect($browser.url()).toEqual('http://server/app/#/Home');
747+
expect($location.path()).toEqual('/Home');
748+
expect($browserUrl.calls.length).toEqual(1);
749+
expect($browserUrl.calls[0].args).toEqual(['http://server/app/#/Home', false, null]);
750+
});
751+
});
752+
753+
it('should not infinite $digest when going to base URL with trailing slash when $locationChangeSuccess watcher changes path to /', function() {
754+
initService({html5Mode: true, supportHistory: false});
755+
mockUpBrowser({initialUrl:'http://server/app/', baseHref:'/app/'});
756+
inject(function($rootScope, $location, $browser) {
757+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
758+
759+
updatePathOnLocationChangeSuccessTo('/');
760+
$rootScope.$digest();
761+
762+
expect($browser.url()).toEqual('http://server/app/#/');
763+
expect($location.path()).toEqual('/');
764+
expect($browserUrl.calls.length).toEqual(1);
765+
});
766+
});
767+
});
768+
769+
770+
describe('location watch for HTML5 browsers', function() {
771+
beforeEach(initService({html5Mode: true, supportHistory: true}));
772+
beforeEach(inject(initBrowser({basePath: '/app/'})));
773+
774+
it('should not infinite $digest when going to base URL without trailing slash when $locationChangeSuccess watcher changes path to /Home', function() {
775+
inject(function($rootScope, $injector, $browser) {
776+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
777+
778+
$browser.url('http://server/app');
779+
$browser.poll();
780+
781+
var $location = $injector.get('$location');
782+
updatePathOnLocationChangeSuccessTo('/Home');
783+
784+
$rootScope.$digest();
785+
786+
expect($browser.url()).toEqual('http://server/app/Home');
787+
expect($location.path()).toEqual('/Home');
788+
expect($browserUrl.calls.length).toEqual(3);
789+
});
790+
});
791+
792+
it('should not infinite $digest when going to base URL without trailing slash when $locationChangeSuccess watcher changes path to /', function() {
793+
inject(function($rootScope, $injector, $browser) {
794+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
795+
796+
$browser.url('http://server/app');
797+
$browser.poll();
798+
799+
var $location = $injector.get('$location');
800+
updatePathOnLocationChangeSuccessTo('/');
801+
802+
$rootScope.$digest();
803+
804+
expect($browser.url()).toEqual('http://server/app/');
805+
expect($location.path()).toEqual('/');
806+
expect($browserUrl.calls.length).toEqual(2);
807+
});
808+
});
809+
810+
it('should not infinite $digest when going to base URL with trailing slash when $locationChangeSuccess watcher changes path to /Home', function() {
811+
inject(function($rootScope, $injector, $browser) {
812+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
813+
814+
$browser.url('http://server/app/');
815+
$browser.poll();
816+
817+
var $location = $injector.get('$location');
818+
updatePathOnLocationChangeSuccessTo('/Home');
819+
820+
$rootScope.$digest();
821+
822+
expect($browser.url()).toEqual('http://server/app/Home');
823+
expect($location.path()).toEqual('/Home');
824+
expect($browserUrl.calls.length).toEqual(2);
825+
});
826+
});
827+
828+
it('should not infinite $digest when going to base URL with trailing slash when $locationChangeSuccess watcher changes path to /', function() {
829+
inject(function($rootScope, $injector, $browser) {
830+
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
831+
832+
$browser.url('http://server/app/');
833+
$browser.poll();
834+
835+
var $location = $injector.get('$location');
836+
updatePathOnLocationChangeSuccessTo('/');
837+
838+
$rootScope.$digest();
839+
840+
expect($browser.url()).toEqual('http://server/app/');
841+
expect($location.path()).toEqual('/');
842+
expect($browserUrl.calls.length).toEqual(1);
843+
});
844+
});
845+
});
846+
675847
});
676848

677849
describe('wiring', function() {
@@ -1040,6 +1212,49 @@ describe('$location', function() {
10401212
}
10411213
);
10421214
});
1215+
1216+
1217+
function mockUpBrowser(options) {
1218+
module(function($windowProvider, $browserProvider) {
1219+
$windowProvider.$get = function() {
1220+
var win = {};
1221+
angular.extend(win, window);
1222+
win.addEventListener = angular.noop;
1223+
win.removeEventListener = angular.noop;
1224+
win.location = {
1225+
href: options.initialUrl,
1226+
replace: function(val) {
1227+
//win.location.href = val;
1228+
}
1229+
};
1230+
return win;
1231+
};
1232+
$browserProvider.$get = function($document, $window, $log, $sniffer) {
1233+
/* global Browser: false */
1234+
var b = new Browser($window, $document, $log, $sniffer);
1235+
b.baseHref = function() {
1236+
return options.baseHref;
1237+
};
1238+
return b;
1239+
};
1240+
});
1241+
}
1242+
1243+
1244+
it('should not get caught in infinite digest when replacing empty path with slash', function() {
1245+
initService({html5Mode:true,supportHistory:false});
1246+
mockUpBrowser({initialUrl:'http://server/base', baseHref:'/base/'});
1247+
inject(
1248+
function($browser, $location, $rootScope, $window) {
1249+
$rootScope.$on('$locationChangeSuccess', function() {
1250+
if ($location.path() !== '/') {
1251+
$location.path('/').replace();
1252+
}
1253+
});
1254+
$rootScope.$digest();
1255+
}
1256+
);
1257+
});
10431258
});
10441259

10451260

0 commit comments

Comments
 (0)