Thursday, 25 December 2014

$rootScope:infdig 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations combination of (Angular js and IE) Bug

In this post we are going to see a concept of infinite digest, that is takes place in the angular js. probably when you see the angular js website they mention it as this kind of error is raised in only two kind of scenario's. i.e is mentioned like below.

        According to the angular js support portal, they mention this kind of error is raised when application model becomes unstable. and each life cycle triggers a state change and subsequent $digest will happen, so to avoid this kind of infinite digest loop, they make a count of 10 after that they stop the digest iteration, and throws the error.Now let we see what are the two scenario's that can happen, i.e mention by them.

Scenario 1 :

Watching a variable change and doing a operation for that change or executing a function for a change, for every execution $digest will execute, But if you certainly change the value of variable which is watched by the same trigger, it will again fires the watch of that variable, so now the $digest is fires endless.In this scenario they will raise a Error like 10 $digest iteration reached.

$scope.$watch('count',function(){
      $scope.count = $scope + 1;        // digest will run for execute a function
});

Scenario 2:

Another scenario is there which will comes in the ng-repeat directive execution, how in this we are getting the $digest iteration, simple instead of give the collection variable in the loop, we are giving a function in ng-repeat which will return a array, so for every execution nr-repeat gets the first value only, so repeatedly we are doing the same process.

<div ng-repeat="emp in getemp()"
{{emp}}
</div>

$scope.getemp = function(){
 return ['suresh','ramesh','ramu'];
};

so we analysis the error causing scenario's now we are going to actually another scenario also causing this same error, actually this is a Bug of angular due to IE.

When we are design a application with angular, we have to keep in mind that every error raised in the angular could be because of angular itself there is a side effects of others things also, like browser, jquery. 


when you are working with 5000 to 6000 lines of angular code that time if you got a error like 

[$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Watchers fired in the last 5 iterations

then the first thing that goes in our mind that we made mistake some we where else, which meets the one of the above two scenario's, so you will actually got stuck in to the every line by line code to find out that loop hole. finally it takes a lot of efforts a day or more than day to find out the root cause which is actually causing this problem.Instead of doing this first find out whether this is really our problem or angular problem. because In Angular there is a Bug which is cause in IE  predominately  below version IE 11, and also in some of the other browsers in older version of angular.

First we see the scenario.

Develop a  application which use the angular js version 1.2.16, then made a code which have a tag with href="#" and along with ngclick which have the functionlity of adding a value for some collection, and that collection is mentioned in a ng-repeat.

Now for this scenario, this works fine and very well for all Browsers other the IE version less than 11

what kind of error will come for IE version less than 11 ?
 you will get a error like


[$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 19; oldVal: 18"],["fn: $locationWatch; newVal: 20; oldVal: 19"],["fn: $locationWatch; newVal: 21; oldVal: 20"],["fn: $locationWatch; newVal: 22; oldVal: 21"],["fn: $locationWatch; newVal: 23; oldVal: 22"]],

In the above error code it tells that it is get raise from the $locationWatch, you may wonder why this error is raising , so you have starts to check for all Watch which is goes wrong, but the issue is not in your code, it is because of placing a code Href="#" in the a tag, This Href makes a location changes , so why the error raises. now we see inside the angular js code.


    // 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;

    });

In the above code in angular js, we can see the changeCounter. will keep on increasing this is because that the # tag mention in the a tag.that makes the $locationWatch to fire

If there are hyperlinks in your App, make sure you handle them properly, and they are doing what you want them to do, because, "href", can cause location change, which your application might not like

If there is no need for HTML5 mode in your app then following code will resolve this issue

    locapp.config(function ($locationProvider) {
        $locationProvider.html5Mode(false).hashPrefix('!');

    });

but if HTML5 mode is needed then do the following

so place href="javascript:void(0);", this will stop the location change and infinite loop stops executes, even after change the code still the $infdigest get then place the Latest Angular version 1.2.28, it is fixed, especially  this issue occurs only in the IE not in the other browsers.


Sometimes it occurs in chrome browsers itself, you can simulate that using the following code, by placing the pushstate in chrome.

javascript:
**********

    var locapp = angular.module('locapp', []);

    locapp.controller('locController', function ($scope, $rootScope) {
        $scope.setLoc = function () {
            history.pushState(null, '', '/index');
            angular.element(document.body).scope().$apply();
        }

    });


HTML:
**********


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body data-ng-app="locapp">

<script id="inc.html" type="text/ng-template">
    <button  ng-click="setLoc()">Set Location</button>
</script>

    <div ng-controller="locController">
        <div ng-include="'inc.html'"></div>
    </div>

<script type="application/javascript" src="js/jquery-2.0.0.min.js"></script>
<script type="application/javascript" src="js/bootstrap.min.js"></script>
<script type="application/javascript" src="js/angular.js"></script>
<script type="application/javascript" src="ang/issue.js"></script>

</body>

</html>


so from the code you can see that the location keep on change result in $infdigest issue in chrome browser itself.


So i think this post may resolve and give a better idea about the $infdigest issue in angualr js.




No comments:

Post a Comment