随机orderBy在AngularJS 1.2中返回'infdig'错误

在这个问题中使用随机orderBysorting技术在AngularJS 1.1中工作正常。

 var myApp = angular.module('myApp',[]); function MyCtrl($scope) { $scope.list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; $scope.random = function() { return 0.5 - Math.random(); } } 

然而,在1.2中,它将infdig错误放入控制台,并花费更长的时间来返回sorting后的结果: http : //jsfiddle.net/mblase75/jVs27/

控制台中的错误如下所示:

 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [["fn: $watchCollectionWatch; newVal: 42; oldVal: 36"],["fn: $watchCollectionWatch; newVal: 47; oldVal: 42"],["fn: $watchCollectionWatch; newVal: 54; oldVal: 47"],["fn: $watchCollectionWatch; newVal: 61; oldVal: 54"],["fn: $watchCollectionWatch; newVal: 68; oldVal: 61"]] 

orderBy的文档没有使用函数expression式的例子,只有stringexpression式。 有什么改变,或者这是一个错误?

我不确定以前的版本,但在当前版本中,在范围上监视的任何expression式(例如传递给ng-repeatexpression式)通常每个摘要至less计算两次。 只有当整个Angular应用程序的所有范围内的所有评估expression式的结果在两个连续评估之间相同时,摘要周期才会结束。

因为每个评价

 <li ng-repeat="i in list | orderBy:random">{{i}}</li> 

导致调用random(),所以不同的顺序,然后Angular将继续评估expression式,直到它达到10个摘要迭代的极限,并抛出一个错误。

解决方法是在控制器中设置模板以外的顺序:

 $scope.list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; $scope.rankedList = []; angular.forEach($scope.list, function(item) { $scope.rankedList.push({ item: item, rank: 0.5 - $window.Math.random() }); }); 

然后按照如下的顺序使用该字段:

 <li ng-repeat="i in rankedList | orderBy:'rank'">{{i.item}}</li> 

这可以在这个jsfiddle看到。

你可以用一个简单的自定义filter以angular度方式解决这个问题。 这里我使用了实现Fischer-Yates的下划线混洗方法。

如果你愿意的话,你可以用你自己的algorithm来代替shuffle的胆量。

 angular.module('shuffle', []) .filter('shuffle', function() { return function(ary) { return _.shuffle(ary); } }); 

现在我们可以通过这个filter来pipe理我们的数组,像这样:

 <li ng-repeat='option in options | shuffle'> 

当模板被渲染时,filter将被调用一次。