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

Passing in an a function to the ngOptions array clause that generates elements on the fly results in infinite $digest loop #9464

Closed
drjokepu opened this issue Oct 7, 2014 · 7 comments

Comments

@drjokepu
Copy link

drjokepu commented Oct 7, 2014

AngularJS 1.2.22 (in particular, commit c286094) has changed the behaviour of ngOptions from deep watching to shallow watching the elements of the array. If the array and its elements are generated by a function on the fly, shallow watching will fail as even if the elements are identical, they are separate instances. This results in infinite $digest loops:

    Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
    Watchers fired in the last 5 iterations: [["fn: $watchCollectionWatch; newVal: 37; oldVal: 32"],["fn: $watchCollectionWatch; newVal: 42; oldVal: 37"],["fn: $watchCollectionWatch; newVal: 47; oldVal: 42"],["fn: $watchCollectionWatch; newVal: 52; oldVal: 47"],["fn: $watchCollectionWatch; newVal: 57; oldVal: 52"]]
    http://errors.angularjs.org/"NG_VERSION_FULL"/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3A%20%24watchCollectionWatch%3B%20newVal%3A%2037%3B%20oldVal%3A%2032%22%5D%2C%5B%22fn%3A%20%24watchCollectionWatch%3B%20newVal%3A%2042%3B%20oldVal%3A%2037%22%5D%2C%5B%22fn%3A%20%24watchCollectionWatch%3B%20newVal%3A%2047%3B%20oldVal%3A%2042%22%5D%2C%5B%22fn%3A%20%24watchCollectionWatch%3B%20newVal%3A%2052%3B%20oldVal%3A%2047%22%5D%2C%5B%22fn%3A%20%24watchCollectionWatch%3B%20newVal%3A%2057%3B%20oldVal%3A%2052%22%5D%5D
        at /Users/tamas/build/github.com/drjokepu/angular.js/src/minErr.js:73:12
        at Scope.$digest (/Users/tamas/build/github.com/drjokepu/angular.js/src/ng/rootScope.js:705:19)
        at Scope.$apply (/Users/tamas/build/github.com/drjokepu/angular.js/src/ng/rootScope.js:931:24)
        at null.<anonymous> (/Users/tamas/build/github.com/drjokepu/angular.js/test/ng/directive/selectSpec.js:1142:15)

A tracking expression clause is supported by ngOptions that explicitly defines the expression that is used for comparing array elements. However, currently this is only used for identifying the selected item and not used for watching the elements of the array itself. I am suggesting extending the usage of this expression to be also used for differentiating of the array items themselves when shallow watching.

Reproducible: always
Browsers: Tested on Chrome 37, Safari 7.1
Operating System: OS X 10.9.5

Steps to reproduce:

  • Create a new html file and add the following content:
<!DOCTYPE html>
<html>
<head>
  <title>Infinite Digest</title>
</head>
<body>
  <body ng-app="demoApp">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
    <script type='text/javascript'>
    angular.module('demoApp', []).controller('DemoController', function($scope) {
      $scope.makeOptions = function() {
          var options = [];
          for (var i = 0; i < 5; i++) {
              options.push({ label: 'Value = ' + i, value: i });
          }
          return options;
      };
      $scope.selected = { label: 'Value = 1', value: 1 };
    });
    </script>
    <div ng-controller="DemoController">
        <div>
            <h2>Infinite Digest</h2>
            <select ng-model="selected"
                ng-options="opt as opt.label for opt in makeOptions() track by opt.value">
            </select>
            The value selected is {{ selected.value }}.
        </div>
    </div>
</body>
</body>
</html>
  • Open this file in a browser. AngularJS will report infinite digest in the console.

This works fine on AngularJS 1.2.21 and earlier.

I am not really an Angular developer (or a real JavaScript developer for that matter), but I am going to submit a pull request with a spec test as well as a proposed solution that will illustrate how I would go about tackling the issue,

@caitp
Copy link
Contributor

caitp commented Oct 7, 2014

#9419 may be partially related to what you want (since currently tracking expressions don't really work at all)

@caitp caitp added this to the Backlog milestone Oct 7, 2014
@caitp caitp removed the 0 - Backlog label Oct 7, 2014
drjokepu added a commit to drjokepu/angular.js that referenced this issue Oct 7, 2014
… of objects in ngOptions

ngOptions does not use the tracking expression when shallow watching array elements passed in to ngOptions. This is a problem if the elements passed in to ngOptions are generated on the fly and while the array elements identical in value, they are different instances; this leads to infinite digest loops. This change attempts to rectify the situation by shallow watching an array of trackFn(values) rather than the array of values themselves.

Closes angular#9464
drjokepu added a commit to drjokepu/angular.js that referenced this issue Oct 7, 2014
… of objects in ngOptions

ngOptions does not use the tracking expression when shallow watching array elements passed in to ngOptions. This is a problem if the elements passed in to ngOptions are generated on the fly and while the array elements identical in value, they are different instances; this leads to infinite digest loops. This change attempts to rectify the situation by shallow watching an array of trackFn(values) rather than the array of values themselves.

Closes angular#9464
drjokepu added a commit to drjokepu/angular.js that referenced this issue Oct 7, 2014
… of objects in ngOptions

ngOptions does not use the tracking expression when shallow watching array elements passed in to ngOptions. This is a problem if the elements passed in to ngOptions are generated on the fly and while the array elements identical in value, they are different instances; this leads to infinite digest loops. This change attempts to rectify the situation by shallow watching an array of trackFn(values) rather than the array of values themselves.

Closes angular#9464
@drjokepu
Copy link
Author

drjokepu commented Oct 7, 2014

Yes, I forgot that I was working on 1.2.26 and not master, rookie mistake, thanks a lot!

petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Jan 11, 2015
@petebacondarwin
Copy link
Contributor

This is fixed by #10639 - see http://plnkr.co/edit/Q4EZDPCyAgUMKoWDPmrE?p=preview

@ipoly
Copy link

ipoly commented May 12, 2015

@petebacondarwin I just try the plunker demo with 1.3.15 and find that it still throw infdig errors.

@Narretz
Copy link
Contributor

Narretz commented Jun 5, 2015

@ipoly the fix is only available in the 1.4.x branch

@Jerryzhao-z
Copy link

@petebacondarwin the plunker demo doesn't work anymore, and I have the same issue of ngOptions

@gkalpak
Copy link
Member

gkalpak commented Oct 18, 2016

@Jerryzhao-z, it is probably because that CI build artifacts are not available any more. Here is the same plnkr using v1.5.8: http://plnkr.co/edit/krNb7CjrQ55i1LeOTJ91?p=preview

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