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

Already on GitHub? Sign in to your account

$location runs into infinite digest under certain circumstances #1417

Closed
IgorMinar opened this Issue Sep 25, 2012 · 86 comments

Comments

Projects
None yet
Owner

IgorMinar commented Sep 25, 2012

when adding Angular to an existing project that makes use of html5 history. Whenever the url is changed outside of Angular, the next $digest to run produces this error:

Error: 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 8; oldVal: 7"],["fn: $locationWatch; newVal: 9; oldVal: 8"],["fn: $locationWatch; newVal: 10; oldVal: 9"],["fn: $locationWatch; newVal: 11; oldVal: 10"],["fn: $locationWatch; newVal: 12; oldVal: 11"]]

I have my own routing in place, using goog.history.Html5History. I was trying to include some Angular stuff on a single page (works), but when the page changes, the first subsequent $apply produces the above error. It looks like the $location service is getting out of sync with the browser.

$locationWatch expects the $location service to be updated first, followed by the browser. But when I pushState to the browser directly, the $location service still has the old url.

The sad thing is that $location is not being used directly by this app, nor is $route. It's ngInclude, that depends on $anchorScroll, which depends on $location - maybe fixing this dependency should be a separate issue... (to be investigated)

Contributor

dbinit commented Sep 25, 2012

Here is a jsFiddle that reproduces the issue: http://jsfiddle.net/dbinit/tMmKf/

I also ran into this bug recently. For me it happened while testing in IE8 with html5Mode(true) (which in IE8 falls back to html5Mode(false), of course).

Contributor

kstep commented Nov 2, 2012

I confirm this bug for AngularJS 1.1.0 and IE9.

fr0 commented Nov 8, 2012

This is also happening to me in Chrome (Version 22.0.1229.94 m), when using window.history.pushState in response to a button click. Angular version: 1.0.2.

Any update to this? Giving us some IE9 headaches.

I am also experiencing this in IE9. Any update?

having the same problem. Still no fix for this?

For what it's worth, I was having this issue in IE9 and Android and here is what I did:

  1. Make sure you have a route to '/' in Angular and that it works properly - for example: $routeProvider.when('/', {templateUrl: 'partials/home', controller: HomeCtrl});

  2. Add $locationProvider.html5Mode(true).hashPrefix('!'); to your app configuration

  3. I had to add the following code to get android to work and I just added it in a script tag before angular loads etc.

var buggyAndroid = parseInt((/android (\d+)/.exec(window.navigator.userAgent.toLowerCase()) || [])[1], 10) < 4;
var buggyAndroid = parseInt((/android (\d+)/.exec(window.navigator.userAgent.toLowerCase()) || [])[1], 10) < 4;
if (!history.pushState || buggyAndroid) {
if (window.location.hash) {
if(window.location.pathname !== '/') window.location.replace('/#!' + window.location.hash.substr(2)); //Hash and a path, just keep the hash (redirect)
} else {
if (window.location.pathname === '/') window.location.replace('/#!/'); //No hash, no path
else window.location.replace('/#!' + window.location.pathname); //No hash, but have a path, take path
}
}

Contributor

dbinit commented Nov 26, 2012

In my case, I wasn't using $location at all. It was just getting pulled in by $anchorScroll, which is used by ngInclude.

I wasn't using $anchorScroll either, so I just did this to remove the dependency:

angular.module('myApp', []).value('$anchorScroll', null);

If you're using $anchorScroll you could probably just null out $location instead.

pgte commented Dec 12, 2012

I'm running into this and I don't have explicit watchers and I don't import $location.
When I do history.pushState(...) I get the following error:

Error: 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: function (){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=\n!1;return o}; newVal: 8; oldVal: 7"],["fn: function (){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=\n!1;return o}; newVal: 9; oldVal: 8"],["fn: function (){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=\n!1;return o}; newVal: 10; oldVal: 9"],["fn: function (){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=\n!1;return o}; newVal: 11; oldVal: 10"],["fn: function (){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=\n!1;return o}; newVal: 12; oldVal: 11"]]
    at Error (<anonymous>)
    at Object.e.$digest (http://localhost:8080/js/lib/angular.min.js:85:217)
    at Object.e.$apply (http://localhost:8080/js/lib/angular.min.js:86:469)
    at HTMLAnchorElement.<anonymous> (http://localhost:8080/js/lib/angular.min.js:140:507)
    at HTMLAnchorElement.v.event.dispatch (http://localhost:8080/js/lib/jquery-1.8.3.min.js:2:38053)
    at HTMLAnchorElement.o.handle.u (http://localhost:8080/js/lib/jquery-1.8.3.min.js:2:33916) 

Any ideas?

Here is an example where the initial page load fails and reloads after throwing the above error.
http://jsfiddle.net/v7HG5/ (Open in IE)

Note: jsfiddle doesn't handle any angular routing, so the rendered view is a blank jsfiddle. Also, nothing will happen at all on an html5 supported browser.

My understanding is that the page is going to need to refresh to convert the url from html5 mode to hash mode (adding the "#" http://jsfiddle.net/#/v7HG5/). In my case this is fine, but it should handle its errors.

Also problem with html5Mode(true) and IE8. Everything works in Chrome/FF, but in IE Angular is unable to bootstrap because the $locationWatcher keeps getting a new value, and thus $digest fails. This results in a redirection loop (for reasons not totally clear to me) where IE keeps redirecting to the "index" page and Angular fails to bootstrap.

Any news on this issue?

Right now the team is contemplating setting html5Mode(false) and rewriting the routing on the server side.

I've managed to reduce the occurance of this bug significantly by using $location.path() and $location.search() instead of manually using location.href. Hope that helps someone else.

@gaiottino were you using angular for routing or an external plugin? because i would love to see the solution for app that uses an external plugin but want to watch the url change

@leonzinger I was iterating an app which relied on crossroads.js and Handlebars to Angular. It worked great for Chrome/FF/Safari, but IE would have $digest problems described above. I've removed crossroads.js now in favor of using Angular for routing but with a patch I'm hoping will make it's way into master: #1901

@gaiottino Thanks a lot for the answer, i would love to see it working with an outside routing library though...

@leonzinger the only part which took some investigation was how to compile Angular specific code. Once you render html with Angular markup you need to compile it. I don't have any code to show but using https://github.com/leshill/handlebars_assets it was basically

template = HandlebarsTemplates[template_name]
html = template()
$(selector).append(html)
compile(selector) if html.has('ng-controller')

Where the compile function is

compile: (selector) ->
  app = angular.element(document)
  compiler = app.injector().get('$compile')
  scope = app.scope()

  elements = angular.element("#{selector} [ng-controller]")
  if elements.exists()
    for el in elements
      element = angular.element(el)
      template = compiler(element)
      html = template(scope)
    scope.$apply() if(!scope.$$phase)

If you plan to render html dynamically you should also destroy any previous controllers that are no longer used

destroy: (selector) ->
  elements = $(selector).find('[ng-controller]')
  for element in elements
    app = angular.element(element)
    if app
      scope = app.scope()
      scope.$destroy() if scope

The app was bootstrapped manually using

$ ->
    angular.bootstrap(document)

In case it is useful... I was hitting the "10 $digest() iterations reached. Aborting!" error when using $window.history.back(); with IE9 (works fine in other browsers of course).

I got it to work by using:

setTimeout(function() {
  $window.history.back();
},100);
Contributor

thebigredgeek commented Feb 25, 2013

Thats not a very good solution though. It isn't guaranteed to work on slower machines. I have ran into a similar issue where I get the digest iteration error on some phonegap devices but not others. Quite bizare. Looking for a work around

Vbahole commented Feb 27, 2013

I'm seeing this as well. Using IE9 and I'm not even using history. I just use $location.search()['searchTerm'] in one of my controllers so that i can capture something from the query string and act on it. Works fine in ff with html5mode=true. in ie9 with mode true it spins then goes to the IIS home page and puts a # in my url. With mode set to false it doesn't perform the qs search.

mezezo commented Feb 28, 2013

I am seeing this on IE9 with angular 1.0.5. Is this by any chance fixed on 1.1.3? Or is there a known workaround?

Contributor

BrainCrumbz commented Mar 8, 2013

We are experiencing the same error on IE9 when invoking $window.history.back(). We tried with plain "window" and it's the same. At this fiddle http://jsfiddle.net/DGbNp/ you can see the first two functions from the Angular error "stack trace" from IE console error. (We edited the output to remove double quotes and \n 's).
For now we could live with dropping completely the "back button", but it's not gonna last long.
If anyone needs more info, please just ask.

sahglie commented Mar 8, 2013

I'm also seeing this on IE9 with angular 1.0.5. Sadly this is a show stopper for our team as far as moving ahead with angular. :-(

Bump, I have the exactly same thing on FF16 and Chrome22 with Angular1.0.5.
This is really a pain in ass.

klebba commented Apr 1, 2013

+1 - 1.1.3 / IE9

Had the same issue recently, manually commenting out 577 - 611 in https://github.com/angular/angular.js/blob/master/src/ng/location.js did do the trick for me...
Obviously this isnt the best solution as modifiying angular's source isn't what should be done actually...

What about adding an option to dis-/enable $location's watch on browser url completely.. something like:

angular.module('myApp', []).config('$locationProvider', function($locationProvider) {
    $locationProvider.disable(); //disables/removes all watchers on browser url change
})

+1 IE8/9

glebm commented Apr 25, 2013

$locationProvider.disable() would be a very useful addition.
Is there a way to remove a listener from scope?

tonypee commented May 16, 2013

Is this being looked at? We are experiencing this exact issue, a solution would be handy - even just the .disable() as we arnt using any routing or location functionality.

EDIT - can confirm that : angular.module('myApp', []).value('$anchorScroll', null); works to remove the dependancies - thanks @dbinit

@ghost

ghost commented May 23, 2013

Bump, very annoying when developing for IE.

Contributor

pvasek commented May 24, 2013

There is similar issue opened (#2007).
Just submitted pull request for that issue #2782.

ceryash commented May 30, 2013

i faced this issue in IE10. have tried all above solutions, but none of them work

I am setting $location.path('somevalue') and getting the same error. It's a pretty big problem as I can't redirect to another location in the controllers.

UPDATE: Fixed it for my particular case. I had <a href="#" ng-click="something()>click</a>. The problem was href="#". Got rid of it and the problem was fixed

I would love to see this issue get resolved.

sparmboy commented Jun 4, 2013

+1 I get this issue in Chrome

sparmboy commented Jun 5, 2013

As I work around, instead of:


$location.path( partialURL );

I set the location directly and append the hash manually:


window.location = window.location.origin + window.location.pathname + "#" + partialURL;

Worked for me...

watsocd commented Jun 7, 2013

I am having this issue on a redirect from PayPal. When the user hits the Buy Now button, the browser is redirected to PayPal. I have tried several methods mentioned above with this redirection with no success.

The error occurs on the return from PayPal after the user has approved the payment on the PayPal site.

The return URL from PayPal looks like: http://somewhere.com/paypalReturn?success=true&token=EC-1XT84966V66999999&PayerID=MNQ67EA999999

The return URL bounces right back into my angular APP to show the purchase confirmation. It works flawlessly in Chrome/Win7. It works in IE10/Win7 with a non-fatal $digest already in progress error. In IE8/XP it locks up the browser in an endless loop as described by others.

In my case I have this issue on several webkit based browsers. I managed to reproduce it with browserstack emulator of iPhone 4 (iOS 4.0) and this plnkr : http://plnkr.co/edit/DFMpOC

The reproduction is not easy, you have to preview the plunkr in a separate window and add a trailing name at the end of the url (for example run.plnkr.co/OHkN002KOzZyrnkh/#/test).

In my case the problem seems to be tied to the use of http backend used in a view resolve phase or in conjunction with a route redirect (this is why you have to add /test in the plunkr url to generate a redirection).

It is not easy to debug in a virtual mobile environment but it seems that the resolve of the http promise trigger an update of the view that triggers an anchorScroll call. Not sure this is the root of the problem but I guess it is.

watsocd commented Jun 10, 2013

I found out right where the error is occurring in angular.js.

Starting at line #5573 in angular.js v 1.0.6.

// update browser
var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var currentReplace = $location.$$replace;

  if (!changeCounter || oldUrl != $location.absUrl()) {
    changeCounter++;
    $rootScope.$evalAsync(function() {
      if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
          defaultPrevented) {
        $location.$$parse(oldUrl);
      } else {
        $browser.url($location.absUrl(), currentReplace);
        afterLocationChange(oldUrl);
      }
    });
  }
  $location.$$replace = false;

  return changeCounter;
});

I think the issue is that changeCounter is being initialized outside the watch and then used inside the watch. I am not a JavaScript expert but I believe the inside the watch is a different scope and changeCounter does not exist inside the scope.

It IE8, the watch runs over and over again because I think changeCounter is not defined properly and does not get incremented with the changeCounter++ line. When I use the IE8 debugger on this code, changeCounter does not appear as one of the local variables.

Contributor

pvasek commented Jun 11, 2013

Have you had anyone chance to try my changed version of angular.js?

#2782

I am really curious if it works only for us or for anyone else as well.

I tried your fix but it does not fix the bug in my case

Contributor

kstep commented Jun 11, 2013

You are right, you are not a JavaScript expert. The snippet works exactly as it should to. The changeCounter variable is caught into closure into $locationWatch function, and as it's defined in outer scope, it's value is preserved between function calls. It's not a local function variable, but it is visible inside function. If you move changeCounter definition inside the function it will be redefined on each function call, which will make it useless. Please read more about JavaScript functions, closures and scopes.

watsocd notifications@github.com wrote:

I found out right where the error is occurring in angular.js.

Starting at line #5573 in angular.js v 1.0.6.
// update browser
var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var currentReplace = $location.$$replace;

if (!changeCounter || oldUrl != $location.absUrl()) { changeCounter++; $rootScope.$evalAsync(function() { if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl). defaultPrevented) { $location.$$parse(oldUrl); } else { $browser.url($location.absUrl(), currentReplace); afterLocationChange(oldUrl); } }); } $location.$$replace = false; return changeCounter; });

I think the issue is that changeCounter is being initialized outside the watch and then used inside the watch. I am not a JavaScript expert but I believe the inside the watch is a different scope and changeCounter does not exist inside the scope.

It IE8, the watch runs over and over again because I think changeCounter is not defined properly and does not get incremented with the changeCounter++ line. When I use the IE8 debugger on this code, changeCounter does not appear as one of the local variables.


Reply to this email directly or view it on GitHub.

@kstep: I agree with your analysis, but @watsocd was making an honest attempt to help. Maybe the slightly condescending tone towards him/her could have been avoided.

watsocd commented Jun 11, 2013

pvasek,

Your change #2782 fixed the issue for me.

Contributor

pvasek commented Jun 11, 2013

@watsocd great, thank you for letting me know.

watsocd commented Jun 11, 2013

When will this change be rolled into the next revision?

@pvasek Your change did work for me but am not using as its not merged. I'll check by latter and see if they have merged it. I was getting this error when IE8 when I try to open a new tab that is also part of my application. If I tell angular about the change first and then open the window it doesn't have the problem. (but may cause others)

$location.url(imosOrmanViewEndPoint + '/#orman_vtb');
window.open(imosOrmanViewEndPoint + '/#orman_vtb', windowName);

This is my first angular project, so is their something wrong with this approach?

Edit: never mind Neither works. :)

Seeing this as well. Did a quick less than ideal workaround involving jQuery and a .lt-ie10 conditional which would set html5Mode to false. I'm only using $location.path and $location.search

IgorMinar added a commit to IgorMinar/angular.js that referenced this issue Jul 24, 2013

fix($location): prevent infinite digest error due to IE bug
If an app uses HTML5 mode and we open an html5 url on IE8 or 9 which
don't support location href, we use location.replace to reload the page
with the hashbang equivalent of the url but this fails with infinite
digest. This is because location.replace doesn't update location.href
synchronously on IE8 and 9.

Closes #2802, #3305, #1417

IgorMinar added a commit that referenced this issue Jul 24, 2013

fix($location): prevent infinite digest error due to IE bug
If an app uses HTML5 mode and we open an html5 url on IE8 or 9 which
don't support location href, we use location.replace to reload the page
with the hashbang equivalent of the url but this fails with infinite
digest. This is because location.replace doesn't update location.href
synchronously on IE8 and 9.

Closes #2802, #3305, #1417

IgorMinar added a commit that referenced this issue Jul 24, 2013

fix($location): prevent infinite digest error due to IE bug
If an app uses HTML5 mode and we open an html5 url on IE8 or 9 which
don't support location href, we use location.replace to reload the page
with the hashbang equivalent of the url but this fails with infinite
digest. This is because location.replace doesn't update location.href
synchronously on IE8 and 9.

Closes #2802, #3305, #1417
Owner

IgorMinar commented Jul 24, 2013

fixed by dca2317

@IgorMinar IgorMinar closed this Jul 24, 2013

The above patch fixed the errors but broke the history for me. Anyone else seeing this behavior? dca2317#commitcomment-3833187

P.S: although it shows alot of errors it seems all seems to work in IE8/IE9 (browser mode, I'm using IE10). I guess for the time being this is better than not having errors and having a broken history...

Contributor

apolishch commented Aug 11, 2013

Note: I am on Angular 1.0.7 and had to apply this patch manually.

I am still having this issue occur after the patch. In my case, changing the line

if ((!changeCounter || oldUrl != $location.absUrl()) {

to

if ((!changeCounter || oldUrl != $location.absUrl() && ($location.absUrl()+'#')!=oldUrl)) {

fixed the issue, though I would love some insight into what it is exactly that I just broke. (Obviously I am using '#' as a path separator, and this could be generalized to pull off $locationProvider config.

Hitting into it with 1.2.0rc1 and UI Router, on IE10. I am using $state.transitionTo("..."). Also $location.path("...") exposes the same behavior. If I type a page URL in browser, I will not get this error the first time, but the second time I type the same URL, I will get it. Any ideas?

Hitting this issue in IE 8 with angular 1.2.0rc1 using $window.history.back().

fraywing commented Sep 6, 2013

I'm using the Zombie headless browser with Node and Angular, and I've tracked the same $digest iteration error down to this very issue.

It seems that instead of making exceptions for each instance of this issue, there should be a permanent and universal solution.

ncraike commented Dec 5, 2013

Should that commit really have closed this issue when it only claims to fix the bug in IE, not Chrome?

raelmax commented Dec 17, 2013

I have the same problem. My page uses the history api and i put a angular app that don't use routes inside her. When a choose the page i receive this error:

Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 8; oldVal: 7"],["fn: $locationWatch; newVal: 9; oldVal: 8"],["fn: $locationWatch; newVal: 10; oldVal: 9"],["fn: $locationWatch; newVal: 11; oldVal: 10"],["fn: $locationWatch; newVal: 12; oldVal: 11"]]

Somebody have a solution to this?

You could try wrapping a timeout around your history api call. I wrapped a short 100ms timeout around my call to back() for example. The code example is on a previous post from 10 months ago.

darkyen commented Jan 3, 2014

Happens in Chrome [latest]. Occurs if you use history.pushState and hence you are doing it wrong 👎 you should use $location.path instead but i wonder how to achive replaceState with location.path ?

This issue should be reopened as its happening on Safari 5.1 and Chrome [latest] for mobile. This is a critical error. It only happens for me when a different page/website performs a javascript redirect to the angular app. Refresh the page and the errors will completely disappear.

The issue can be reproduced using AngularJS v1.2.13 in IE9, IE10, when calling $window.history.back() (especially in Windows Phone).

It seems the root cause is that $window.history.back() in IE changes the href right before the $locationWatch() is fired hence oldUrl would contain the new Url and that throws off the angular into an infinite $digest.

The immediate work around is to replace the calls to $window.history.back() with the following:

setTimeout(function () {
$window.history.back();
}, 0);

I just hit this, when trying to emulate legacy browsers not supporting HTML5 [1]. Was trying to test the HTML5 mode fallback. Using Chrome.

So, apparently, you can reproduce this quite easily using Angular and Chrome by decorating the $sniffer service and setting history to false.

myApp.config(function($httpProvider, $locationProvider, $provide) {
    $httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content');
    $locationProvider.html5Mode(true);
    $provide.decorator('$sniffer', function($delegate) {
        $delegate.history = false;
        return $delegate;
    });
});

[1] - As suggested here: http://stackoverflow.com/questions/16677528/location-switching-between-html5-and-hashbang-mode-link-rewriting

Another repro case: load two modules (either via manual bootstrap and ng-app, or both via manual bootstrap) that make use of $location and trigger any sort of location change. Both $location instances will fight over which one has the right url.

Well we ran into that problem (IE 11) also when trying to navigate with $location.path('target');

After debugging in IE as well as FF we discovered, that IE doesn't update the lastBrowserUrl like FF does (angular.js line 4406). So commenting out that line (if (lastBrowserUrl == url) return;) does solve the problem everywhere we discovered it. The downsite is obviously an overhead in navigation - which we did not recognize at all.

It's just a possible workaround i wanted to share.

swlasse commented Jul 1, 2014

@lord2800 Thanks for mentioning that - I have struggled with the exact same issue for hours now. In my case, I have two apps bootstrapped using ng.bootstrap(). My workaround has been to skip using $location in one of the apps and use window.location as fallback instead.

Running angular v1.2.16, Chrome 35.0.1916.153.

lord2800 commented Jul 1, 2014

@swlasse that's exactly what we ended up doing as well. Glad to be of help!

almaron commented Jul 2, 2014

This watch generates the same error on pageload. It's a simple pagination watch on a forum topic show page.
$window.history.pushState is the trigger, though it is only called once (I've checked it with console.log). any ideas?

$scope.$watch("postPagination.cur", function(newVal, oldVal) {
  if (angular.isDefined(newVal) && newVal && (newVal !== oldVal)) {
    $window.history.pushState({
      page: newVal,
      prev: oldVal
    }, "", $scope.currentPath + "?page=" + newVal);
    $scope.loadPosts(newVal);
  }
});

Okay, I couldn't find an exact answer, so this is what worked for me (hopefully it helps someone else).

This is occurring for me in AngularJS v1.2.22.

In IE8 / IE9 I get the $rootScope:infdig from using window.location = 'XYZ'; to change the URL. It works fine in Chrome/FF/Safari, just not IE.

The solution for me was to simply use $location.

Ex:

Instead of:

window.location = '/#!/test123/';

Use:

$location.path('test123').replace();

I have this issue with the 1.3.0-rc.0 version.

alehro commented Sep 9, 2014

@rbygrave Thank you, your workaround works for me with delay = 500 ms. 100 ms doesn't help.

I encountered this issue in the context of manually bootstrapping my app, as I forgot to remove hg-app directive, which basically leads to location watch infinite digest breakdown. So I can case you are encountering this problem under uncertain circumstances better double check that first.

mhayes14 commented Oct 6, 2014

I am running into this problem when doing my own routing. ngRoute has been removed from the app.

I run something like history.pushState(null, null, '/some/page'); to set the current page state and then when the digest runs it hits the infinite error:

10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: function (){var a=d.url(),b=g.$$replace;r&&a==g.absUrl()||(r++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",g.absUrl(),a).defaultPrevented?g.$$parse(a):(d.url(g.absUrl(),b),h(a))}));\ng.$$replace=!1;return r}; newVal: 42; oldVal: 41"],["fn: function (){var a=d.url(),b=g.$$replace;r&&a==g.absUrl()||(r++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",g.absUrl(),a).defaultPrevented?g.$$parse(a):(d.url(g.absUrl(),b),h(a))}));\ng.$$replace=!1;return r}; newVal: 43; oldVal: 42"],["fn: function (){var a=d.url(),b=g.$$replace;r&&a==g.absUrl()||(r++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",g.absUrl(),a).defaultPrevented?g.$$parse(a):(d.url(g.absUrl(),b),h(a))}));\ng.$$replace=!1;return r}; newVal: 44; oldVal: 43"],["fn: function (){var a=d.url(),b=g.$$replace;r&&a==g.absUrl()||(r++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",g.absUrl(),a).defaultPrevented?g.$$parse(a):(d.url(g.absUrl(),b),h(a))}));\ng.$$replace=!1;return r}; newVal: 45; oldVal: 44"],["fn: function (){var a=d.url(),b=g.$$replace;r&&a==g.absUrl()||(r++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",g.absUrl(),a).defaultPrevented?g.$$parse(a):(d.url(g.absUrl(),b),h(a))}));\ng.$$replace=!1;return r}; newVal: 46; oldVal: 45"]]

I could do with some way to stop Angular from listening to anchor clicks too, which I guess is related to this problem as it's listening for location changes so that it can fire $locationChangeStart etc.

richardm commented Oct 7, 2014

Also having this same issue using Angular UI Router...

sgarbesi commented Oct 7, 2014

@bluehayes @richardm did you try what I mentioned? If you attempt to change the url/history without $location angular goes haywire.

What fixed the infinite redirecting issue for us was removing the "otherwise" block, from our routeProvider. We have a unique situation of 2 angularJS applications running in the same page, so this fix might not be the fix for everyone.

This problem appeared with migration to 1.3 and was related to injecting $location into a service. It was happily working before the change. Used the suggestion by @swlasse (cheers) to get around the problem.

elemoine commented Feb 4, 2015

dca2317, which closed that issue, does not fix the problem raised by @IgorMinar in this issue's initial description. @IgorMinar, the issue you described in #1417 (using "Angular in an existing project that makes use of html5 history (goog.history.Html5History for example) is not IE-specific at all.

This is a major issue. This makes Angular in my way, even when I don't use the $location service.

elemoine commented Feb 5, 2015

The only workaround I've found involves monkey-patching the $location provider's $get function. By changing the $get function we prevent the provider from installing the problematic watches. See camptocamp/ngeo#160. I'd really like to fix Angular instead, but, at this point, I don't know what a proper fix would look like.

In my app I don't use $location and I patch this issue with this decoration:

 $provide.decorator('$location', ['$delegate', '$browser', function($delegate, $browser){
      $delegate.absUrl = function(){return $browser.url();};
      return $delegate;
 }]);

azachar commented May 5, 2015

Thank you, @smirnovigor ! Well, it works and it doesn't work too. With UI-Router it doesn't replace the url with a new state's url...

azachar commented May 5, 2015

Hmm, I did simple think and it seems me to that it really helped. I do some redirection after a user logged in and simply wrapping my redirect call into setTimeout method help with the $location event loop.

setTimeout(function({
$location.path('....')
},500);

Not elegant, but it works!

caviles commented May 13, 2015

You guys are so awesome changing window.replace to $location.path(url_step2_view); worked amazingly. THANKSSSSSSS!!!!!!!!!!

fredrikengstrom added a commit to sklintyg/statistik that referenced this issue Aug 17, 2015

STATISTIK-1211 Fixat en oändlig loop som kunde uppstå i IE11 om man f…
…ortsatte att försöka öppna nya rapporter efter att användaren blivit utloggad. Lösning enligt diskussion här: angular/angular.js#1417

Thanks @azachar! Your timeout workaround helped in my case.

@azachar's timeout workaround worked for me too.

@smirnovigor You are the MAN! Been working on this for 2 days! The decorator works everyone!

leye0 commented Nov 10, 2015

@caviles You didn't solve a bug, you weren't using $location. This bug is about $location.

natee commented May 3, 2016

In my case, I used window.location.href = 'xxx', when I changed it to $location.path(), It worked fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment