angularjs infinite $ digest当没有范围改变时循环

foi*_*rth 11 javascript infinite-loop angularjs

我的角度代码中出现以下错误.我很难理解为什么函数getDrawWithResults会导致一个摘要周期,因为似乎没有任何副作用?它只返回属性设置为true的列表中的项.

只有首次使用getDrawWithResults在页面上时才会出现错误,如果我删除,则错误停止.

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"]]
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

HTML

<h4 ng-cloak ng-hide="getDrawsWithResults(selectedLottery.draws)">Results of Selected Lottery</h4>

<div class="con" ng-repeat="draw in getDrawsWithResults(selectedLottery.draws)" ng-cloak>
    <h5 class="con__header">[[ draw.date|date:'EEEE d MMMM yyyy - H:mm' ]]</h5>
    <div class="balls-list__outer con__row">
        <div class="balls-list">
            <div class="balls-list__ball__outer" ng-repeat="b in draw.results">
                <button class="balls-list__ball btn btn-con">[[ b ]]</button>
            </div>

        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JS

// return list of draws with results
$scope.getDrawsWithResults = function(draws) {
    return _.filter(draws, function(draw){
        return draw.results && draw.results.length > 0;
    });
}
Run Code Online (Sandbox Code Playgroud)

Kos*_*rov 14

我假设_.filter每次运行时都返回一个新的数组实例.这会导致角度的隐式$watches,如:

ng-hide="getDrawsWithResults(selectedLottery.draws)"
Run Code Online (Sandbox Code Playgroud)

ng-repeat="draw in getDrawsWithResults(selectedLottery.draws)"
Run Code Online (Sandbox Code Playgroud)

认为模型已经改变,所以它需要再次消化.

我会实现一个过滤器

app.filter('withResults', function() {
    return function(draws) {
        return _.filter(draws, function(draw){
            return draw.results && draw.results.length > 0;
        });
    }
})
Run Code Online (Sandbox Code Playgroud)

并应用它(见下面的编辑):

ng-hide="selectedLottery.draws | withResults"
Run Code Online (Sandbox Code Playgroud)

ng-repeat="draw in selectedLottery.draws | withresults"
Run Code Online (Sandbox Code Playgroud)

在评论中讨论后编辑

实际问题是这种绑定:

ng-hide="getDrawsWithResults(selectedLottery.draws)"
Run Code Online (Sandbox Code Playgroud)

ng-hide注册一个将永远激发的手表,因为过滤后的阵列的引用总是会改变.它可以改为:

ng-hide="getDrawsWithResults(selectedLottery.draws).length > 0"
Run Code Online (Sandbox Code Playgroud)

和相应的过滤器:

ng-hide="(selectedLottery.draws | withResults).length > 0"
Run Code Online (Sandbox Code Playgroud)

ng-repeat没有相同的问题,因为它注册了一个$watchCollection.


Kay*_*ave 7

这意味着$scope.getDrawsWithResults()不是幂等的.给定相同的输入和状态,它不会始终返回相同的结果.并且ng-hide需要幂等函数(与Angular有关的所有函数一样).

简而言之,使用返回单个布尔结果而不是_.filter返回数组的函数可能会更好.也许_.all吧?

幂等性在这里起作用的原因是因为Angular的$ digest循环的工作方式.因为你的ng-hideAngular会监视你的结果$scope.getDrawsWithResults().通过这种方式,只要应该重新评估,就可以发出警报ng-hide.您ng-repeat不会受到影响,因为Angular不需要观察结果.

因此,每次$ digest发生时(每秒多次)都会$scope.getDrawsWithResults()被调用,以查看它的结果是否与之前的$ digest周期有所不同,从而是否应该更改ng-hide.如果结果已经改变,Angular知道这也可能意味着它正在观察的其他函数(可能使用你的函数的结果)可能已经改变了.所以它需要重新运行$ digest(如果需要,让变化传播通过系统).

所以$ digest一直在运行,直到它正在观看的所有函数的结果停止变化.或者直到有10美元的消化周期.Angular假设如果系统在10个周期后不稳定,它可能永远不会稳定.所以它放弃并抛出你得到的错误信息.

如果您愿意,可以在这里深入探讨这一切:http: //teropa.info/blog/2013/11/03/make-your-own-angular-part-1-scopes-and-digest. HTML