我从我的后端服务器接收数据结构如下:
{ name : "Mc Feast",owner : "Mc Donalds" },{ name : "Royale with cheese",{ name : "Whopper",owner : "Burger King" }
对于我的看法,我想“倒转”的列表。也就是说我想列出每个所有者,并为该所有者列出所有汉堡包。我可以通过使用underscorejs函数groupBy在一个过滤器,然后使用与ng-repeat指令:
JS:
app.filter("ownerGrouping",function() { return function(collection) { return _.groupBy(collection,function(item) { return item.owner; }); } });
HTML:
<li ng-repeat="(owner,hamburgerList) in hamburgers | ownerGrouping"> {{owner}}: <ul> <li ng-repeat="burger in hamburgerList | orderBy : 'name'">{{burger.name}}</li> </ul> </li>
这工作作为预期,但我得到一个巨大的错误堆栈跟踪,当列表呈现与错误消息“10 $ digest迭代达到”。我很难看到我的代码如何创建一个无限循环,这是由这条消息隐含的。有没有人知道为什么?
这里是一个链接到plunk与代码:http://plnkr.co/edit/8kbVuWhOMlMojp0E5Qbs?p=preview
这是因为_.groupBy在每次运行时返回一个新对象的集合。 Angular的ngRepeat没有意识到这些对象是相等的,因为ngRepeat通过标识跟踪它们。新对象导致新的身份。这使得Angular认为自从上一次检查以来发生了一些变化,这意味着Angular应该运行另一个检查(也称为摘要)。下一个摘要最终得到另一组新的对象,因此触发另一个摘要。重复直到Angular放弃。
一个简单的方法来摆脱错误是确保你的过滤器返回相同的对象集合每次(除非当然它已经改变)。你可以很容易地用下划线使用_.memoize。只需在memoize中包含过滤函数:
app.filter("ownerGrouping",function() { return _.memoize(function(collection,field) { return _.groupBy(collection,function(item) { return item.owner; }); },function resolver(collection,field) { return collection.length + field; }) });
如果您计划对过滤器使用不同的字段值,则需要解析器函数。在上面的示例中,使用数组的长度。最好是将集合减少到唯一的md5哈希字符串。
See plunker fork here. Memoize将记住特定输入的结果,并返回相同的对象,如果输入与之前相同。如果值经常变化,那么你应该检查_.memoize是否丢弃旧的结果,以避免内存泄漏的时间。
进一步调查,我看到ngRepeat支持扩展语法…跟踪通过EXPRESSION,这可能是有帮助的某种方式允许你告诉Angular看看餐厅的所有者,而不是对象的身份。这将是一个替代上面的memoization手法,虽然我不能设法测试它在plunker(可能的老版本的Angular从跟踪之前被实现?)。