用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 以外依然有效,則必須在控制器中也進行過濾,這就須要一些不是很必要的重複代碼。 值得慶幸的是本文中介紹的模式能夠用來避免這種狀況。