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

$location runs into infinite digest under certain circumstances #1417

Closed

Description

@IgorMinar

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)

Activity

  1. dbinit commented on Sep 25, 2012

    @dbinit
    Contributor

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

  2. martinstein commented on Oct 29, 2012

    @martinstein

    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).

  3. kstep commented on Nov 2, 2012

    @kstep
    Contributor

    I confirm this bug for AngularJS 1.1.0 and IE9.

  4. fr0 commented on Nov 8, 2012

    @fr0

    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.

  5. gaiottino commented on Nov 14, 2012

    @gaiottino

    Any update to this? Giving us some IE9 headaches.

  6. scottweinert commented on Nov 23, 2012

    @scottweinert

    I am also experiencing this in IE9. Any update?

  7. ThomasDeutsch commented on Nov 26, 2012

    @ThomasDeutsch

    having the same problem. Still no fix for this?

  8. scottweinert commented on Nov 26, 2012

    @scottweinert

    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
    }
    }

  9. dbinit commented on Nov 26, 2012

    @dbinit
    Contributor

    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.

  10. pgte commented on Dec 12, 2012

    @pgte

    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?

  11. brandonsalmon commented on Jan 3, 2013

    @brandonsalmon

    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.

  12. ThomasBorghs commented on Feb 7, 2013

    @ThomasBorghs

    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.

  13. gaiottino commented on Feb 7, 2013

    @gaiottino

    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.

  14. leonzinger commented on Feb 10, 2013

    @leonzinger

    @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

  15. gaiottino commented on Feb 11, 2013

    @gaiottino

    @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

  16. 63 remaining items

  17. toblender commented on Oct 15, 2014

    @toblender

    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.

  18. camden-kid commented on Nov 4, 2014

    @camden-kid

    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.

  19. elemoine commented on Feb 4, 2015

    @elemoine

    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.

  20. elemoine commented on Feb 5, 2015

    @elemoine

    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.

  21. smirnovigor commented on Mar 23, 2015

    @smirnovigor

    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;
     }]);
    
  22. azachar commented on May 5, 2015

    @azachar

    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...

  23. azachar commented on May 5, 2015

    @azachar

    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!

  24. caviles commented on May 13, 2015

    @caviles

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

  25. M0ns1gn0r commented on Sep 4, 2015

    @M0ns1gn0r

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

  26. creativegeekjp commented on Sep 19, 2015

    @creativegeekjp

    @azachar's timeout workaround worked for me too.

  27. comfroels commented on Sep 22, 2015

    @comfroels

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

  28. leye0 commented on Nov 10, 2015

    @leye0

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

  29. natee commented on May 3, 2016

    @natee

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions