用ng-repeat指令遍历一个javascript数组,当数组中有重复元素的时候,angularjs会报错,这是由于ng-Repeat不容许collection中存在两个相同Id的对象。javascript
对于数字或者字符串等基本数据类型来讲,它的id就是它自身的值。所以数组中是不容许存在两个相同的数字的。为了规避这个错误,须要定义本身的track by表达式。java
// 业务上本身生成惟一的id
item in items track by item.idgit//或者直接拿循环的索引变量$index来用
item in items track by $indexangularjs
Error: [ngRepeat:dupes]
这个出错提示具体到题主的状况,意思是指数组中有2个以上的相同数字。ngRepeat不容许collection中存在两个相同Id的对象先来看看一个完整有效的ng-repeat
示例。github
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items"> {{item.name}} <button ng-click="remove($index)">remove</button> </li> </ul>
对应的控制器(controller)以下:api
app.controller('ListCtrl', ['$scope', function($scope) { //items come from somewhere, from where doesn't matter for this example $scope.items = getItems(); $scope.remove = function(index) { var item = $scope.items[index]; removeItem(item); }; }]);
看起来没什么问题,对吗? 这段代码也没有任何特别值得注意的。数组
而后,让咱们来作一个小小的修改: 给列表添加一个过滤器。 这是很常见的作法,若是列表很长的话,例如容许用户进行搜索。app
为了方便起见, 假设咱们经过 searchFilter
来查询列表中的记录。函数
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items | searchFilter"> {{item.name}} <button ng-click="remove($index)">remove</button> </li> </ul>
控制器的代码保持不变。 看起来仍然没有问题,是吧?测试
事实上,有一个bug藏在里面。 若是我不说, 你能找到吗? 若是能找到,你就已是Angular大牛了.
$index
BUG实际上是在控制器里面:
$scope.remove = function(index) { var item = $scope.items[index]; removeItem(item); };
这里使用了 index参数, 而后就遇到了BUG: 过滤后的索引(indexs)不匹配原始列表的索引。
幸运的是,有一个很简单的方法来避免这种问题: 不要使用$index
,而改为实际的item对象。
<ul ng-controller="ListCtrl"> <li ng-repeat="item in items | searchFilter"> {{item.name}} <button ng-click="remove(item)">remove</button> </li> </ul>
控制器以下所示:
$scope.remove = function(item) { removeItem(item); };
注意, 这里将 remove($index)
改为 remove(item)
, 并修改了 $scope.remove
函数来直接操做传过来的对象。
这个小小的修改就彻底避免了刚才的BUG。
为了更好地说明问题以及解决方案,请参考 interactive example 。
第一个教训固然是在使用 $index
要当心一点,由于以某些方式使用时极可能会产生BUG。
第二个教训是,请记住相似这样的模式,则能够用更好的作事方式,能够彻底避免某些类型的BUG。 我强烈建议你们如今不要使用 $index
, 从这种简单的思惟转变中,就能够减小代码中的不少BUG。
第三个教训是测试并非何时都有用。 即使有自动化测试,也覆盖了足够多的情形, 但对于依赖特定输入的状况,也很容易错过某些BUG。 错误自己并非每次都会出现,即便你也用过滤来测试。
第四个教训是不要破坏抽象 —— 这一点很容易被忽略。理论上 $index
是由 ng-repeat
建立的一个 “模板变量(template variable)”。 这只在 repeat 块里面有意义(并正确起做用)。 当咱们将它的值传递到外面时,它就失去了上下文从而再也不有效。 若是确实想让它在 repeat 以外依然有效,则必须在控制器中也进行过滤,这就须要一些不是很必要的重复代码。 值得庆幸的是本文中介绍的模式能够用来避免这种状况。