0

我有一个选择列表,其中的内容是从第一个选择列表中选择的内容动态生成的。我似乎无法找到为什么每次更改第一个选择列表时都会触发这些错误:

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn:
regularInterceptedExpression","newVal":42,"oldVal":37},{"msg":"fn:       regularInterceptedExpression","newVal":"16","oldVal":"14"}],[{"msg":"fn: regularInterceptedExpression","newVal":47,"oldVal":42},{"msg":"fn: regularInterceptedExpression","newVal":"18","oldVal":"16"}],[{"msg":"fn: regularInterceptedExpression","newVal":52,"oldVal":47},{"msg":"fn: regularInterceptedExpression","newVal":"20","oldVal":"18"}],[{"msg":"fn: regularInterceptedExpression","newVal":57,"oldVal":52},{"msg":"fn: regularInterceptedExpression","newVal":"22","oldVal":"20"}],[{"msg":"fn: regularInterceptedExpression","newVal":62,"oldVal":57},{"msg":"fn: regularInterceptedExpression","newVal":"24","oldVal":"22"}]]
http://errors.angularjs.org/1.4.7/$rootScope/infdig?p0=10&p1=%5B%5B%7B%22ms…Expression%22%2C%22newVal%22%3A%2224%22%2C%22oldVal%22%3A%2222%22%7D%5D%5D

另外,每次更改列表时,每次更改列表都会触发多次用于生成第二个列表的“makeOptions”。

这两个列表的设置如下:

    <select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options"></select>
    <select ng-model="selected.level2" ng-options="opt.value as opt.label for opt in makeOptions()"></select>

控制器是:

app.controller('DemoController', function($scope) {

  $scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
  $scope.makeOptionsCallCount = 1;
  $scope.selected = {};


  $scope.makeOptions = function() {

    console.log($scope.makeOptionsCallCount++);

    var options = [];

    for (var i = 0; i < 5; i++) {
        options.push({ label: 'Value = ' + i + $scope.selected.level1, value: i + $scope.selected.level1 });
    }

    return options;
  };

});

这是一个奇怪的例子:

http://plnkr.co/edit/mKv7nMjot5XqBj4mkvhR?p=preview

有什么想法我哪里出错了吗?

更新

我可能过度简化了我遇到麻烦的例子。解决方案变得更加复杂,因为我有一个项目列表,您可以为每个项目选择一组值。对不起,我在问我原来的问题时忽略了这个元素。

我创建了更准确地反映这一点的新示例:

http://plnkr.co/edit/I62WepJVLuuqN0YbCafD?p=preview

4

2 回答 2

1

当您在视图中使用函数时,它会在每个摘要循环上执行。

还有角度添加观察者来产生这个函数,例如,如果你在每次调用时返回新数组 - 你会进入无限循环,因为[] != []

在您的情况下,您还有另一个错误:在视图中调用的内部函数更改了变量,该变量也显示在视图中。所以对于这个变量也加了watcher。

你在函数调用中改变值,观察变量改变,再次运行摘要,运行函数,改变值,看到变量改变等等......

因此,对于解决方案,首先选择更改时更好的简单保存选项。

var app = angular.module('demoApp', [])
    
    app.controller('DemoController', function($scope) {
      
      $scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
      $scope.makeOptionsCallCount = 1;
      $scope.selected = {};
      
      
      $scope.makeOptions = function(lvl) {
        
        $scope.options = []; 
        console.log(++$scope.makeOptionsCallCount);

        for (var i = 0; i < 5; i++) {
            $scope.options.push({ label: 'Value = ' + i + lvl, value: i + lvl });
        }
        
      };

    });
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script>
    <div ng-app="demoApp" ng-controller="DemoController">
      <div>
        
        <h2>Infinite Digest 2</h2>
        
        <select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options" ng-change="makeOptionsCallCount=0;makeOptions(selected.level1)"></select>
        
        <select ng-model="selected.level2" ng-options="opt.value as opt.label for opt in options"></select>

        <br/>
        <br/>
        <div>Level 1: {{selected.level1}}</div>
        <div>Level 2: {{selected.level2}}</div>
        <div>makeOptions() Called: {{makeOptionsCallCount}} times</div>
      </div>
    </div>

更新:
就您的评论而言,您可以利用在ng-change事件ng-repeat上创建的创建自己的范围并将列表选项保存到其中的事实。

此外,您甚至可以使用您的功能makeOptions

ng-change可以传递表达式:

ng-change="optionsLvLs = makeOptions(option.level1)"

ng-repeat每个选项的范围内,如果这很重要,将创建optionsLvLs不会污染您的选项对象的更改事件。

    var app = angular.module('demoApp', [])
    
    app.controller('DemoController', function($scope) {
      
      $scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
      $scope.selected = {};
      $scope.options = [{ name: "A" }];

      $scope.makeOptions = function(level1) {
        
        var options = [];
        
        for (var i = 0; i < 5; i++) 
        { 
          options.push({ label: 'Value = ' + i + level1, value: i + level1 }); 
        }
        
        return options;
      };

      $scope.addQuery = function(idx) {
        $scope.options.splice(idx + 1, 0, {});
      };

      $scope.removeQuery = function (idx) {
        $scope.options.splice(idx, 1);
      };


    });
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.js"></script>
<div ng-controller="DemoController" ng-app="demoApp">
  <div>

    <h2>Infinite Digest 2</h2>

    <div ng-repeat="option in options">

      <input type="button" value="+" ng-click="addQuery($index)" />
      <input type="button" value="-" ng-click="removeQuery($index)" />

      <select ng-model="option.level1" ng-options="lvl.name as lvl.name for lvl in level1options" ng-change="optionsLvLs = makeOptions(option.level1)"></select>
      <select ng-model="option.level2" ng-options="opt.value as opt.label for opt in optionsLvLs"></select>

      <br/>
      <br/>

    </div>

  </div>

  {{ options }}

</div>

于 2015-11-03T04:06:27.977 回答
0

进行以下更改不需要调用函数来动态创建数据:

$scope.level1options = [{ name: "A", value: "A" }, { name: "B", value: "B" }, { name: "C", value: "C" }];
$scope.level2options = [0,1,2,3,4];

<select ng-model="selected.level1" ng-options="lvl.name as lvl.name for lvl in level1options"></select>
<select ng-model="selected.level2" ng-options="i+selected.level1 as 'Value = '+i+selected.level1 for i in level2options"></select>

这是 plunker:http ://plnkr.co/edit/GQhnjTpB0sLHoiSnchhn?p=preview

于 2015-11-03T04:08:05.923 回答