5

在这个问题中使用随机orderBy排序技术在 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错误放入控制台并需要更长的时间才能返回排序结果: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没有使用函数表达式的示例,只有字符串表达式。有什么变化,还是这是一个错误?

4

2 回答 2

9

我不确定以前的版本,但在当前版本中,在范围上观察的任何表达式,例如传递给的表达式,ng-repeat通常每个摘要至少评估两次。只有当整个 Angular 应用程序的所有范围内的所有评估表达式的结果在两次连续评估之间都相同时,摘要循环才会结束。

因为每次评价

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

导致调用 random(),因此顺序不同,然后 Angular 将继续评估表达式,直到达到 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看到。

于 2014-02-05T20:04:00.583 回答
2

您可以使用简单的自定义过滤器以 Angular 的方式解决此问题。在这里,我使用了实现 Fischer-Yates 的下划线 shuffle 方法。

如果您愿意,可以用您自己的算法替换 shuffle 的内容。

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

我们现在可以通过这个过滤器来管道我们的数组,如下所示:

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

渲染模板时将调用过滤器一次。

于 2014-11-13T18:10:17.863 回答