Làm cách nào để xóa một mục hoặc đối tượng khỏi một mảng bằng ng-click?


261

Tôi đang cố gắng viết một chức năng cho phép tôi loại bỏ một mục khi nhấp vào nút nhưng tôi nghĩ rằng tôi đang bị lẫn lộn với chức năng - tôi có sử dụng $digestkhông?

HTML & app.js:

<ul ng-repeat="bday in bdays">
  <li>
    <span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
    <form ng-show="editing" ng-submit="editing = false">
      <label>Name:</label>
      <input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
      <label>Date:</label>
      <input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
      <br/>
      <button class="btn" type="submit">Save</button>
      <a class="btn" ng-click="remove()">Delete</a>
    </form>
  </li>
</ul>

$scope.remove = function(){
  $scope.newBirthday = $scope.$digest();
};

2
Bạn không muốn $ digest, vì nó được sử dụng để vào vòng lặp digest của Angular (và bạn đã ở trong vòng lặp digest vì nhấp chuột ng). Bạn đang cố gắng để loại bỏ một mục từ một mảng?
Mark Rajcok 16/03/13

@MarkRajcok :) vâng đó là những gì tôi đang cố gắng thực hiện
Jess McKenzie

remove()trong ng-clickcách bạn có nó không có ngữ cảnh. Cần thêm chi tiết trong đánh dấu để hiển thị những gì đang bị xóa và nếu nó ở trong ng-repeathoặc nơi mục bị xóa đến hoặc hành vi bạn muốn từremove()
charlietfl 16/03/13

@charlietfl nó nằm trong ng-repeat Tôi đã cập nhật câu hỏi
Jess McKenzie

Đây là 1 bài viết của tôi giải thích cách xóa bản ghi với ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh

Câu trả lời:


552

Để xóa mục bạn cần xóa nó khỏi mảng và có thể chuyển bdaymục vào chức năng xóa của bạn trong đánh dấu. Sau đó, trong trình điều khiển tìm kiếm chỉ mục của mục và loại bỏ khỏi mảng

<a class="btn" ng-click="remove(item)">Delete</a>

Sau đó, trong bộ điều khiển:

$scope.remove = function(item) { 
  var index = $scope.bdays.indexOf(item);
  $scope.bdays.splice(index, 1);     
}

Angular sẽ tự động phát hiện sự thay đổi của bdaysmảng và thực hiện cập nhậtng-repeat

DEMO: http://plnkr.co/edit/ZdShIA?p=preview

EDIT: Nếu thực hiện cập nhật trực tiếp với máy chủ sẽ sử dụng dịch vụ bạn tạo bằng cách $resourcequản lý cập nhật mảng đồng thời cập nhật máy chủ


62
Sử dụng $indextrực tiếp có thể tạo ra lỗi nếu danh sách của bạn được lọc trên mẫu. Đó là một điều mẫu; nó là an toàn hơn để sử dụng ng-click='remove(bday)'sau đóarr.splice(arr.indexOf(bday),1);
Umur Kontacı

6
Bạn không cần phải vượt qua $ index vì bạn có thể sử dụng 'this' bên trong phương thức. $ scope.remove = function () {$ scope.bdays.splice (this. $ index, 1); }
matchdav

1
@matthewdavidson this is undefined. Plunker / jsfiddle có lẽ?
Tjorriemorrie

11
.indexOf(item)sẽ trả về -1 nếu không tìm thấy, điều này có thể dẫn đến việc xóa mục ở cuối mảng nếu bạn không kiểm tra.
Ben Wilde

1
@ShibinRagh đọc tài liệu cho Array.prototype.splice ()
charlietfl

54

Đây là một câu trả lời đúng:

<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove=function($index){ 
  $scope.bdays.splice($index,1);     
}

Trong câu trả lời của @ charlietfl. Tôi nghĩ đó là sai vì bạn vượt qua $indexnhư paramter nhưng thay vào đó bạn sử dụng điều ước trong bộ điều khiển. Sửa lỗi cho tôi nếu tôi sai :)


có vẻ như cả hai câu trả lời đều tương đương nhau, mặc dù hàm của bạn có thể chấp nhận chỉ mục mà không có $ và nó vẫn hoạt động.
svarog

đây phải là câu trả lời đúng indexOfCHỈ hoạt động nếu đó là IE9 +
levi

17
Điều này sẽ không hoạt động nếu bạn có một đơn đặt hàng hoặc bộ lọc trong lần lặp lại của bạn
Joan-Diego Rodriguez

Điều này sẽ hoạt động tốt hơn, nếu bạn đã sử dụng theo dõi bởi $ index
Ankit Balyan

@ Joan-DiegoRodriguez Làm thế nào bạn có thể làm cho nó hoạt động nếu bạn có bộ lọc / trật tự Đừng bận tâm chỉ cần đọc Câu trả lời
XMLille

26

Trong trường hợp bạn đang ở trong một lặp lại ng

bạn có thể sử dụng một tùy chọn lót

    <div ng-repeat="key in keywords"> 
        <button ng-click="keywords.splice($index, 1)">

            {{key.name}}
        </button>
    </div>

$index được sử dụng bởi angular để hiển thị chỉ số hiện tại của mảng bên trong ng-repeat


1
Tôi thích và sử dụng một lớp lót này
etoricky

24

Sử dụng $indexhoạt động hoàn toàn tốt trong các trường hợp cơ bản và câu trả lời của @ charlietfl là tuyệt vời. Nhưng đôi khi,$index không đủ.

Hãy tưởng tượng bạn có một mảng duy nhất, mà bạn đang trình bày ở hai ng-repeat khác nhau. Một trong những ng-repeat đó được lọc cho các đối tượng có thuộc tính trung thực và đối tượng kia được lọc cho thuộc tính giả. Hai mảng được lọc khác nhau đang được trình bày, xuất phát từ một mảng gốc duy nhất. (Hoặc, nếu nó giúp hình dung: có lẽ bạn có một mảng người và bạn muốn một lần lặp lại cho phụ nữ trong mảng đó và một lần nữa cho những người đàn ông trong cùng một mảng .) Mục tiêu của bạn: xóa đáng tin cậy khỏi mảng ban đầu, sử dụng thông tin từ các thành viên của các mảng được lọc.

Trong mỗi mảng được lọc, $ index sẽ không phải là chỉ mục của mục trong mảng ban đầu. Nó sẽ là chỉ mục trong mảng con được lọc . Vì vậy, bạn sẽ không thể nói chỉ mục của người đó trong peoplemảng ban đầu , bạn sẽ chỉ biết chỉ số $ từ womenhoặcmen mảng mảng phụ. Cố gắng xóa bằng cách sử dụng và bạn sẽ có các mục biến mất từ ​​mọi nơi trừ nơi bạn muốn. Phải làm sao?

Nếu bạn đủ may mắn khi sử dụng mô hình dữ liệu bao gồm một mã định danh duy nhất cho từng đối tượng, thì hãy sử dụng mô hình đó thay vì $ index, để tìm đối tượng và splice nó ra khỏi mảng chính. (Sử dụng ví dụ của tôi dưới đây, nhưng với định danh duy nhất đó.) Nhưng nếu bạn không may mắn như vậy?

Angular thực sự tăng từng mục trong một mảng lặp lại ng (trong mảng chính, mảng gốc) với một thuộc tính duy nhất được gọi $$hashKey. Bạn có thể tìm kiếm mảng ban đầu cho một trận đấu trên$$hashKey mục bạn muốn xóa và loại bỏ nó theo cách đó.

Lưu ý rằng $$hashKey là một chi tiết triển khai, không được bao gồm trong API được xuất bản cho ng-repeat. Họ có thể loại bỏ hỗ trợ cho tài sản đó bất cứ lúc nào. Nhưng có lẽ là không. :-)

$scope.deleteFilteredItem = function(hashKey, sourceArray){
  angular.forEach(sourceArray, function(obj, index){
    // sourceArray is a reference to the original array passed to ng-repeat, 
    // rather than the filtered version. 
    // 1. compare the target object's hashKey to the current member of the iterable:
    if (obj.$$hashKey === hashKey) {
      // remove the matching item from the array
      sourceArray.splice(index, 1);
      // and exit the loop right away
      return;
    };
  });
}

Gọi với:

ng-click="deleteFilteredItem(item.$$hashKey, refToSourceArray)"

EDIT: Sử dụng một chức năng như thế này, phím nào $$hashKeythay vì tên thuộc tính dành riêng cho mô hình, cũng có lợi thế đáng kể về việc làm cho chức năng này có thể sử dụng lại trên các mô hình và bối cảnh khác nhau. Cung cấp cho nó với tham chiếu mảng của bạn, và tham chiếu mục của bạn, và nó sẽ chỉ hoạt động.


10

Tôi thường viết theo phong cách như vậy:

<a class="btn" ng-click="remove($index)">Delete</a>


$scope.remove = function(index){
  $scope.[yourArray].splice(index, 1)
};

Hy vọng điều này sẽ giúp Bạn phải sử dụng dấu chấm (.) Giữa $ scope và [yourArray]


Ý nghĩa của "1" trong (chỉ mục, 1)
ShibinRagh

@ShibinRagh Đó là deleteCount. Một số nguyên chỉ số lượng phần tử mảng cũ cần loại bỏ. Nếu xóaCount là 0, không có phần tử nào bị xóa. Trong trường hợp này, bạn nên chỉ định ít nhất một yếu tố mới. Nếu xóaCount lớn hơn số phần tử còn lại trong mảng bắt đầu khi bắt đầu, thì tất cả các phần tử cho đến cuối mảng sẽ bị xóa. Tài liệu Array.prototype.splice ()
ᴍᴀᴛᴛ

9

Dựa trên câu trả lời được chấp nhận, điều này sẽ làm việc với ngRepeat,filter và xử lý expections tốt hơn:

Điều khiển:

vm.remove = function(item, array) {
  var index = array.indexOf(item);
  if(index>=0)
    array.splice(index, 1);
}

Lượt xem:

ng-click="vm.remove(item,$scope.bdays)"

Bạn đã không gán, "xóa" cho $ scope.vm trong bộ điều khiển của mình, vì vậy mã này sẽ không hoạt động. Bây giờ nếu bạn đã làm điều này ... $ scope.vm = {remove: function () {...}}, thì nó sẽ như vậy.
Justin Russo

4

thực hiện mà không có bộ điều khiển.

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

<script>
  var app = angular.module("myShoppingList", []); 
</script>

<div ng-app="myShoppingList"  ng-init="products = ['Milk','Bread','Cheese']">
  <ul>
    <li ng-repeat="x in products track by $index">{{x}}
      <span ng-click="products.splice($index,1)">×</span>
    </li>
  </ul>
  <input ng-model="addItem">
  <button ng-click="products.push(addItem)">Add</button>
</div>

<p>Click the little x to remove an item from the shopping list.</p>

</body>
</html>

Phương thức splice () thêm / xóa các mục vào / từ một mảng.

array.splice(index, howmanyitem(s), item_1, ....., item_n)

chỉ số : Bắt buộc. Một số nguyên chỉ định tại vị trí cần thêm / xóa các mục, Sử dụng các giá trị âm để chỉ định vị trí từ cuối mảng.

howmanyitem (s) : Tùy chọn. Số lượng các mặt hàng sẽ được gỡ bỏ. Nếu được đặt thành 0, sẽ không có mục nào bị xóa.

item_1, ..., item_n : Tùy chọn. (Các) mục mới sẽ được thêm vào mảng


1
Đây là câu trả lời đúng. Tại sao phải dựa vào bộ điều khiển để thực hiện các cuộc gọi JavaScript đơn giản?
Elle Fie

3

Tôi không đồng ý rằng bạn nên gọi một phương thức trên bộ điều khiển của bạn. Bạn nên sử dụng một dịch vụ cho bất kỳ chức năng thực tế nào và bạn nên xác định các chỉ thị cho bất kỳ chức năng nào về khả năng mở rộng và mô đun hóa, cũng như chỉ định một sự kiện nhấp có chứa một cuộc gọi đến dịch vụ mà bạn đưa vào chỉ thị của mình.

Vì vậy, ví dụ, trên HTML của bạn ...

<a class="btn" ng-remove-birthday="$index">Delete</a>

Sau đó, tạo một chỉ thị ...

angular.module('myApp').directive('ngRemoveBirthday', ['myService', function(myService){
    return function(scope, element, attrs){
        angular.element(element.bind('click', function(){
            myService.removeBirthday(scope.$eval(attrs.ngRemoveBirthday), scope);  
        };       
    };
}])

Sau đó, trong dịch vụ của bạn ...

angular.module('myApp').factory('myService', [function(){
    return {
        removeBirthday: function(birthdayIndex, scope){
            scope.bdays.splice(birthdayIndex);
            scope.$apply();
        }
    };
}]);

Khi bạn viết mã đúng như thế này, bạn sẽ dễ dàng viết các thay đổi trong tương lai mà không phải cơ cấu lại mã của mình. Nó được tổ chức hợp lý và bạn đang xử lý các sự kiện nhấp tùy chỉnh một cách chính xác bằng cách ràng buộc bằng cách sử dụng các chỉ thị tùy chỉnh.

Chẳng hạn, nếu khách hàng của bạn nói, "này, bây giờ hãy làm cho nó gọi máy chủ và làm bánh mì, sau đó bật lên một phương thức." Bạn sẽ có thể dễ dàng chỉ cần truy cập vào dịch vụ mà không cần phải thêm hoặc thay đổi bất kỳ mã phương thức HTML và / hoặc mã điều khiển nào. Nếu bạn chỉ có một dòng trên bộ điều khiển, cuối cùng bạn sẽ cần sử dụng một dịch vụ, để mở rộng chức năng để nâng vật nặng hơn mà khách hàng yêu cầu.

Ngoài ra, nếu bạn cần một nút 'Xóa' khác ở nơi khác, giờ đây bạn có thuộc tính chỉ thị ('ng-remove-birthday'), bạn có thể dễ dàng gán cho bất kỳ yếu tố nào trên trang. Điều này bây giờ làm cho nó mô-đun và tái sử dụng. Điều này sẽ có ích khi xử lý mô hình các thành phần web HEAVY của Angular 2.0. Không có bộ điều khiển trong 2.0. :)

Chúc mừng phát triển !!!



0

nếu bạn có ID hoặc bất kỳ trường cụ thể nào trong mục của bạn, bạn có thể sử dụng bộ lọc (). hành động của nó như ở đâu ().

<a class="btn" ng-click="remove(item)">Delete</a>

trong bộ điều khiển:

$scope.remove = function(item) { 
  $scope.bdays = $scope.bdays.filter(function (element) {
                    return element.ID!=item.ID
                });
}

0
Pass the id that you want to remove from the array to the given function 

từ bộ điều khiển (Chức năng có thể nằm trong cùng một bộ điều khiển nhưng thích giữ nó trong một dịch vụ)

    function removeInfo(id) {
    let item = bdays.filter(function(item) {
      return bdays.id=== id;
    })[0];
    let index = bdays.indexOf(item);
    data.device.splice(indexOfTabDetails, 1);
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.