2013-06-02 17 views
10
$scope.clearCompleted = function() 
     { 
      angular.forEach($scope.todos, function(todo, i) 
      { 
       if(todo.done) 
       { 
        $scope.todos.splice(i, 1); 
       } 
      }); 

      if($scope.todos.length == 0) 
      { 
       $scope.isEmpty = true; 
      } 
     } 

這是我的代碼刪除「完成」待辦事項從一個數組, 但是當後兩個彼此待辦事項被去除,它僅去除第二。 我認爲這是因爲拼接函數重置並返回拼接數組。剪接功能遞減索引

+0

是,'.splice()'變異的數組。如果使用前向迭代,這需要考慮。 –

回答

18

您從數組中重新拼接元素,因此減少了「todos」中的索引。對不起,我的英語不好。

var notDonedTodos = []; 
angular.forEach($scope.todos, function(todo, i) 
{ 
    if(!todo.done) 
    { 
     notDonedTodos.push(todo); 
    } 
}); 

$scope.todos = notDonedTodos; 
+0

謝謝你,你太棒了! – jvakuiler

18

這是發生,因爲forEach只知道數組的初始狀態,因此調用你的方法兩次,即使在第一次調用從數組中刪除的項目。只要做一個簡單的while循環,而不是:

var i = $scope.todos.length; 
while (i--){ 
    if ($scope.todos[i].done){ 
     $scope.todos.splice(i, 1); 
    } 
} 
+0

值得指出的是,這個解決方案中的訣竅是數組正在以相反的順序處理,使我們可以忽略數組長度的波動性。這同樣適用於傳統的for循環。 –

3

each迭代的問題是,它從陣列引起迭代要跳過刪除的項目。 jQuery有一個不錯的grep方法,該方法返回所有匹配由提供的匿名函數確定的特定條件的元素。

var todos =[{id:1, done:false},{id:2, done:true},{id:3, done:true}]; 

function removeCompleted(todos){ 
    return $.grep(todos,function(todo){ 
     return todo.done == false; 
    }); 
} 

todos = removeCompleted(todos); 
console.log(todos); 

工作實例http://jsfiddle.net/ktCEN/

Documentation

2

作爲另一種選擇,你可能只是每次做splice時間遞減索引。例如:

$scope.clearCompleted = function() { 
    angular.forEach($scope.todos, function(todo, i) { 
     if(todo.done) { 
      $scope.todos.splice(i, 1); 
      i--; 
     }; 
    }); 

    if($scope.todos.length == 0) { 
     $scope.isEmpty = true; 
    }; 
} 

這會調整您的索引,以便在每次修改陣列時保持其有效性。您仍然可以使用angular.forEach,並且最終不會得到陣列的兩個副本。

7

我發現自己的替代方法是使用array.filter方法。這是基於對象鍵過濾數組最簡單的方法。如果你正在開發一個IE8項目(可憐的你),你需要爲這個函數添加一個polyfill,因爲它對於JavaScript來說是相當新穎的。

Everything you need to know about javascript

回答代碼:

$scope.clearCompleted = function() { 
    $scope.todos = $scope.todos.filter(function(item) { 
     return !item.done; 
    }); 
} 
+0

優秀的解決方案 – Clint