" 10 $ digest()迭代达成。正在中止!",但$ scope未更新

时间:2017-07-18 21:52:10

标签: angularjs

我设法创建一个开箱即用的小样本,可以重现问题。它是一个过滤器,可以从数组中随机删除2个元素:

<!DOCTYPE html>
<html ng-app='myApp'>
  <head>
    <meta charset="utf-8" />
    <script src="https://code.angularjs.org/1.6.5/angular.js"></script>
    <script>
    angular.module('myApp', [])
    .filter('random', function() {
        return function(input) {

            var a = Math.floor(Math.random()*input.length);
            var b = Math.floor(Math.random()*input.length);
            return input.filter(function(element, i){
                if (i !== a && i !== b){
                    return element;
                }
            });
        };
    })
    .controller('Controlleur', function($scope) {
        $scope.contacts = [
            {"name": "donatello", "tel": 12456},
            {"name": "michaelangelo", "tel": 12456},
            {"name": "leonardo", "tel": 12456},
            {"name": "raphael", "tel": 12456},
            {"name": "robert", "tel": 12456},
        ]
    });
    </script>
</head>
<body  ng-controller="Controlleur">
    <ul>
        <li ng-repeat="contact in contacts|random track by contact.name ">
            <strong>{{contact.name}}</strong>: {{contact.tel}}
        </li>
    </ul>
</body>
</html>

将其复制/粘贴到文件中,在浏览器中加载文件,然后打开控制台。如果您按F5几次,您会看到过滤器有效,但您会随机获得:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":21,"oldVal":18},{"msg":"fn: regularInterceptedExpression","newVal":"raphael"},{"msg":"fn: regularInterceptedExpression","newVal":"12456"},{"msg":"fn: regularInterceptedExpression","newVal":"robert"},{"msg":"fn: regularInterceptedExpression","newVal":"12456"}],
...

问题在于它通常意味着连续多次触发$ digest。但是,我不会在任何地方明确更新范围。我只是在过滤器中创建一个新阵列,副作用非常明显。

2 个答案:

答案 0 :(得分:2)

由于你在每个摘要中返回数组中的随机项,因此范围永远不会稳定(每次都是相同的数组)并且继续进行摘要寻找它以稳定它然后它会达到它的限制和中止。

修复方法是在控制器中使用$filter()进行一次随机化,然后再传递新的已过滤数组以查看并删除视图中的随机过滤器

.controller('Controlleur', function($scope, $filter) {
    $scope.contacts = [
        {"name": "donatello", "tel": 12456},
        {"name": "michaelangelo", "tel": 12456},
        {"name": "leonardo", "tel": 12456},
        {"name": "raphael", "tel": 12456},
        {"name": "robert", "tel": 12456},
    ];

    $scope.randomContacts = $filter('random')($scope.contacts);

});

查看:

<li ng-repeat="contact in randomContacts track by contact.name ">
     <strong>{{contact.name}}</strong>: {{contact.tel}}
</li>

DEMO

答案 1 :(得分:0)

我实际上找到了比@ charlietfl更好的解决方案(对于我的用例):在闭包中缓存过滤器级别的随机结果,并在摘要期间将其返回给随机结果。当我需要一个新的随机值时,我就可以破解缓存,无论如何我在$ interval中做了。

我告诉他“接受的回答”标志,因为他解释了为什么,而不仅仅是如何。