2013-06-02 57 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; 
      } 
     } 

Đây là mã của tôi để xóa các 'làm' todos từ một mảng, nhưng khi hai todos sau mỗi khác được loại bỏ, nó chỉ loại bỏ các thứ hai. Tôi nghĩ rằng đó là vì chức năng ghép nối reset và trả về mảng ghép nối.Javascript nối chức năng bên trong vòng lặp foreach decrements index

+0

Có, '.splice()' đột biến một mảng. Điều này cần phải được tính toán nếu sử dụng lặp lại chuyển tiếp. –

Trả lời

18

Bạn ghép các phần tử khỏi mảng mà bạn đã lặp lại, do đó các chỉ mục trong "todos" bị giảm. Xin lỗi vì tiếng Anh của tôi không tốt.

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

$scope.todos = notDonedTodos; 
+0

Cảm ơn người đàn ông, bạn thật tuyệt! – jvakuiler

18

này đang xảy ra vì forEach chỉ biết về tình trạng ban đầu của mảng, và do đó gọi phương pháp của bạn hai lần, ngay cả khi cuộc gọi đầu tiên loại bỏ một mục từ mảng. Chỉ cần làm một cách đơn giản trong khi vòng lặp thay vì:

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

Thật đáng để chỉ ra rằng mẹo trong giải pháp này là mảng đang được xử lý theo thứ tự ngược lại, cho phép chúng ta bỏ qua biến động của độ dài của mảng. Điều này cũng không kém phần hợp lệ với vòng lặp truyền thống. –

3

Vấn đề với each lặp là nó loại bỏ một mục từ mảng gây ra lặp đi lặp lại để được bỏ qua. jQuery có một phương thức tốt đẹp grep trả về tất cả các phần tử khớp với một tiêu chí nhất định được xác định bởi một hàm ẩn danh được cung cấp.

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); 

làm việc Ví dụhttp://jsfiddle.net/ktCEN/

Documentation

2

Là một thay thế, bạn có thể chỉ giảm giá trị chỉ số của bạn mỗi khi bạn làm một splice. Ví dụ:

$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; 
    }; 
} 

Điều này sẽ điều chỉnh chỉ mục của bạn để duy trì tính hợp lệ của mỗi lần sửa đổi mảng. Bạn vẫn có thể sử dụng angular.forEach và bạn không kết thúc với hai bản sao của mảng của mình.

7

Cách thay thế mà tôi đã thấy là sử dụng phương thức array.filter. Đây là cách dễ nhất để lọc một mảng dựa trên các khóa đối tượng. Nếu bạn đang làm việc trên một dự án IE8 (nghèo bạn), bạn sẽ cần phải thêm một polyfill cho chức năng này vì nó khá mới với JavaScript.

Everything you need to know about javascript.

đang trả lời:

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

Giải pháp tuyệt vời – Clint

Các vấn đề liên quan