在ng-repeat中出现的angular无限$digest循环问题

7

我希望在ng-repeat属性中调用函数,以下是我的代码:

示例

HTML:

<body ng-controller="mainCtrl">
  <div ng-repeat='item in getGroupedRange() track by item.id'>
    <span>{{item.val}}</span>
    <span>{{item.abs}}</span>
    <span>{{item.rel}}</span>
    <span>{{item.cum}}</span>
  </div>
</body>

js

$scope.getGroupedRange = function() {
    return [
      {
        val: 1,
        abs: 1,
        rel: 1,
        cum: 1,
        id: 123456
      }
    ];
  };

当我打开控制台时,我注意到了这个错误。
10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: function (c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}","newVal":9,"oldVal":8}],[{"msg":"fn: function (c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}","newVal":10,"oldVal":9}],[{"msg":"fn: function (c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}","newVal":11,"oldVal":10}],[{"msg":"fn: function (c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}","newVal":12,"oldVal":11}],[{"msg":"fn: function (c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}","newVal":13,"oldVal":12}]]

我的代码的主要目标是在每个事件循环中使用 ng-repeat 中的函数来计算数据。

可能是重复的问题:如何使用ng-repeat循环遍历函数返回的项? - Tristan
@Tristan 从你的链接中无法使用hashKey。所以... - Alexey Sh.
жҲ‘зӣёдҝЎпјҢhashKeyе’Ңtrack byйғҪдёҺйҮҚеӨҚдёӯзҡ„йЎ№зӣ®зҡ„DOMжёІжҹ“еӨ„зҗҶпјҲжҲ–жңӘеӨ„зҗҶпјүжңүе…ігҖӮж— йҷҗеҫӘзҺҜй—®йўҳжҳҜз”ұдәҺngRepeatеңЁеҶ…йғЁдҪҝз”Ё$watchCollectionпјҢеӣ жӯӨдјҡжҚ•жҚүж–°ж•°з»„дёӯзҡ„ж–°еҜ№иұЎжүҖеҜјиҮҙзҡ„гҖӮ - bingles
4个回答

7
不,你不能像这样在ngRepeat中使用函数。问题在于Angular在digest循环中严格比较对象以确定自上次检查以来属性的值是否已更改。因此,每次调用getGroupedRange时都会返回值(新数组)。Angular不知道这一点,并将此值视为不稳定,因此继续检查。但是它在进行10次检查后中止。
您需要构造必要的数组并将其分配给作用域属性,以便在digest循环期间不会更改。
$scope.groupedRange = $scope.getGroupedRange();

然后像在ngRepeat中一样使用它

  <div ng-repeat='item in groupedRange track by item.id'>
    <span>{{item.val}}</span>
    <span>{{item.abs}}</span>
    <span>{{item.rel}}</span>
    <span>{{item.cum}}</span>
  </div>

为什么“track by”解决的问题与此无关? - dfsq
当然,我指的是仅限于我的情况。 - Alexey Sh.
它将先前的值(来自上一次检查)与新值进行比较。getGroupedRange()每次返回新的数组。 - dfsq
比较的方式是这样的 == - Alexey Sh.
它使用严格的 ===。但无论如何,getGroupedRange() !== getGroupedRange() - dfsq
显示剩余2条评论

0

Angular会在数据变化时进行计算并自动在模板中显示。但是通过将ng-repeat='item in getGroupedRange()放入无限循环计算中。

尝试通过将列表中可能被$scope.getGroupedRange函数以任何方式更改的项目的值分配给某些作用域变量(例如$scope.range),来避免这种情况,该变量将在ng-repeat中迭代。

在控制器中

$scope.getGroupedRange = function() {
    $scope.range =  [
      {
        val: 1,
        abs: 1,
        rel: 1,
        cum: 1,
        id: 123456
      }
    ];
  };

在模板中

 <div ng-repeat='item in range track by item.id'>
    <span>{{item.val}}</span>
    <span>{{item.abs}}</span>
    <span>{{item.rel}}</span>
    <span>{{item.cum}}</span>
  </div>

什么时候应该调用getGroupedRange函数?我不想在每个地方都粘贴getGroupedRange()...谢谢。 - Alexey Sh.
你需要的时候调用它。 - shershen
我不想重复自己。 - Alexey Sh.
只有在数组中有类似项时才需要使用“track by”,它不会影响我们在此解决的其他部分。 - shershen

0
找到了解决方案:
  $scope.prev = null;
  $scope.getGroupedRange = function() {
    var data = [{
      val: 1,
      abs: 1,
      rel: 1,
      cum: 1,
      id: 123456
    }];
    if (angular.equals($scope.prev, data)) {
      return $scope.prev;
    }
    $scope.prev = data;
    return data;
  };

1
这里的讨论是为了向您解释在ng-repeat中使用函数是一种不好的做法。但是,在Angular世界中,您总是可以找到一种方法来自我毁灭。 - shershen
@shershen 为什么你认为在 ng-repeat 中使用函数是一种不好的实践? - Alexey Sh.
2
@shershen 我认为在函数上使用ng-repeat并不是不好的做法。相反,它与函数式编程非常契合。另一方面,这里的讨论显示了Angular在FP方面的糟糕表现。 - Petkovsky
突变成员并稍后返回它如何是功能性的?哈哈。 - Jay

0

尝试像这样做:

<body ng-controller="mainCtrl">
    <div ng-init="grpRange = getGroupedRange()">
        <div ng-repeat='item in grpRange track by item.id'>
            <span>{{item.val}}</span>
            <span>{{item.abs}}</span>
            <span>{{item.rel}}</span>
            <span>{{item.cum}}</span>
        </div>
    </div>
</body>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接