在angular.js conditional markup in ng-repeat之后,我尝试创作一个自定义过滤器来进行分组。我遇到了有关对象标识和正在观察更改的模型的问题,但我认为我最终将其钉在了一起,因为控制台中不再出现任何错误。
原来我错了,因为现在当我尝试将它与其他过滤器(用于分页)结合起来时就像这样
<div ng-repeat="r in blueprints | orderBy:sortPty | startFrom:currentPage*pageSize | limitTo:pageSize | group:3">
<div ng-repeat="b in r">
我得到了可怕的“10 $ digest()迭代次数。堕胎!”错误消息。
这是我的群组过滤器:
filter('group', function() {
return function(input, size) {
if (input.grouped === true) {
return input;
}
var result=[];
var temp = [];
for (var i = 0 ; i < input.length ; i++) {
temp.push(input[i]);
if (i % size === 2) {
result.push(temp);
temp = [];
}
}
if (temp.length > 0) {
result.push(temp);
}
angular.copy(result, input);
input.grouped = true;
return input;
};
}).
请注意在输入中使用angular.copy
和.grouped
标记,但无济于事:(
我知道例如 "10 $digest() iterations reached. Aborting!" due to filter using angularjs但显然我没有得到它。
此外,我猜分组逻辑有点天真,但这是另一个故事。任何帮助将不胜感激,因为这让我发疯。
答案 0 :(得分:15)
这看起来真正的问题是你正在改变你的输入,而不是创建一个新的变量并从你的过滤器输出。这将触发监视任何正在观察您输入的变量的内容。
确实没有理由在其中添加“分组== true”检查,因为您应该完全控制自己的过滤器。但是,如果这对您的应用程序来说是必须的,那么您需要在过滤器的结果中添加“grouped == true”,而不是输入。
过滤器的工作方式是他们改变输入并返回不同的内容,然后下一个过滤器处理前面的过滤器结果...所以你的“过滤”检查主要是无效的item in items | filter1 | filter2 | filter3
其中filter1过滤项目, filter2过滤filter1的结果,filter3过滤过滤器2的结果......如果这是有意义的。
这是我刚刚掀起的事情。我不确定它是否有效,但它给你基本的想法。你在一边拿一个数组,然后在另一边吐出一个数组。
app.filter('group', function(){
return function(items, groupSize) {
var groups = [],
inner;
for(var i = 0; i < items.length; i++) {
if(i % groupSize === 0) {
inner = [];
groups.push(inner);
}
inner.push(items[i]);
}
return groups;
};
});
HTML
<ul ng-repeat="grouping in items | group:3">
<li ng-repeat="item in grouping">{{item}}</li>
</ul>
修改强>
也许在您的代码中看到所有这些过滤器会更好,但看起来它会导致问题,因为它经常需要在$ digest上重新评估。所以我建议你做这样的事情:
app.controller('MyCtrl', function($scope, $filter) {
$scope.blueprints = [ /* your data */ ];
$scope.currentPage = 0;
$scope.pageSize = 30;
$scope.groupSize = 3;
$scope.sortPty = 'stuff';
//load our filters
var orderBy = $filter('orderBy'),
startFrom = $filter('startFrom'),
limitTo = $filter('limitTo'),
group = $filter('group'); //from the filter above
//a method to apply the filters.
function updateBlueprintDisplay(blueprints) {
var result = orderBy(blueprints, $scope.sortPty);
result = startForm(result, $scope.currentPage * $scope.pageSize);
result = limitTo(result, $scope.pageSize);
result = group(result, 3);
$scope.blueprintDisplay = result;
}
//apply them to the initial value.
updateBlueprintDisplay();
//watch for changes.
$scope.$watch('blueprints', updateBlueprintDisplay);
});
然后在你的标记中:
<ul ng-repeat="grouping in blueprintDisplay">
<li ng-repeat="item in grouping">{{item}}</li>
</ul>
......我确信那里有拼写错误,但那是基本的想法。
再次编辑:我知道您已经接受了这个答案,但还有一种方法可以做到这一点我最近了解到您可能会更喜欢:
<div ng-repeat="item in groupedItems = (items | group:3 | filter1 | filter2)">
<div ng-repeat="subitem in items.subitems">
{{subitem}}
</div>
</div>
这会在你的$ scope上创建一个名为$ scope.groupedItems的新属性,它应该有效地缓存你过滤的和分组的结果。
给它一个旋转,让我知道它是否适合你。如果没有,我想其他答案可能会更好。
答案 1 :(得分:3)
无论如何,我仍然看到$ digest错误,这令人费解:plnkr.co/edit/tHm8uYfjn8EJk3cG31DP - 肉体1月22日17:21
以下plunker分叉了$ digest错误的修正,使用下划线的memoize函数:http://underscorejs.org/#memoize。
问题在于Angular尝试在每次迭代期间将过滤后的集合作为不同的集合进行处理。要确保过滤器的返回始终返回相同的对象,请使用memoize。
http://en.wikipedia.org/wiki/Memoization
使用下划线进行分组的另一个示例:Angular filter works but causes "10 $digest iterations reached"
答案 2 :(得分:1)
您可以使用angular.filter模块的groupBy过滤器,
并做这样的事情:
用法:(key, value) in collection | groupBy: 'property'
或'propperty.nested'
的 JS:强>
$scope.players = [
{name: 'Gene', team: 'alpha'},
{name: 'George', team: 'beta'},
{name: 'Steve', team: 'gamma'},
{name: 'Paula', team: 'beta'},
{name: 'Scruath', team: 'gamma'}
];
<强> HTML:强>
<ul ng-repeat="(key, value) in players | groupBy: 'team'" >
Group name: {{ key }}
<li ng-repeat="player in value">
player: {{ player.name }}
</li>
</ul>
<!-- result:
Group name: alpha
* player: Gene
Group name: beta
* player: George
* player: Paula
Group name: gamma
* player: Steve
* player: Scruath