Як видалити елемент або об’єкт із масиву за допомогою ng-клацання?


261

Я намагаюся записати функцію, яка дозволяє мені видаляти елемент, коли натискається кнопка, але я думаю, що я плутаюсь із функцією - чи користуюся я $digest?

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
Ви не хочете $ digest, оскільки він використовується для введення циклу дайджесту Angular (а ви вже в циклі дайджесту через натискання ng). Ви намагаєтесь видалити елемент із масиву?
Марк Райкок

@MarkRajcok :) так ось що я намагаюся зробити
Джесс Маккензі

remove()у ng-clickвас це не має контексту. Потрібно більше деталей у розмітці, щоб показати, що видаляється і чи знаходиться всередині ng-repeat, або звідки виходить елемент, або від якої поведінки ви хочетеremove()
charlietfl

@charlietfl це в межах ng-повтору Я оновив питання
Jess McKenzie

Ось моя стаття 1, в якій пояснюється, як видалити запис за допомогою ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh

Відповіді:


551

Щоб вилучити елемент, потрібно вийняти його з масиву і передати bdayелемент до функції видалення за розміткою. Потім в контролері шукайте індекс елемента і виймайте з масиву

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

Потім у контролері:

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

Кутовий автоматично виявить зміни в bdaysмасиві та здійснить оновленняng-repeat

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

РЕДАКТУВАННЯ: Якщо робити оновлення з сервером в реальному часі, буде використовуватися створена вами послуга, $resourceщоб керувати оновленнями масиву, одночасно він оновлює сервер


62
Використання $indexбезпосередньо може генерувати помилки, якщо ваш список відфільтровано за шаблоном. Це шаблонна річ; безпечніше використання ng-click='remove(bday)'потімarr.splice(arr.indexOf(bday),1);
Umur Kontacı

6
Вам не потрібно передавати $ index, оскільки ви можете використовувати "це" всередині методу. $ range.remove = function () {$ range.bdays.splice (це. $ index, 1); }
matchdav

1
@matthewdavidson this is undefined. Plunker / jsfiddle можливо?
Tjorriemorrie

11
.indexOf(item)поверне -1, якщо не буде знайдено, це може призвести до видалення елемента в кінці масиву, якщо ви не перевірите його.
Бен Уайльд

1
@ShibinRagh читає документи для Array.prototype.splice ()
charlietfl

54

Це правильна відповідь:

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

У відповіді @ charlietfl Я думаю, що це неправильно, оскільки ти $indexпередаєш параметр, але замість цього використовуєш бажання в контролері. Виправте мене, якщо я помиляюся :)


схоже, що обидві відповіді є рівнозначними, хоча ваша функція може приймати індекс без $, і він все одно буде працювати.
сварог

це має бути правильна відповідь. indexOfТІЛЬКИ працює, якщо це IE9 +
levi

17
Це не спрацює, якщо у вас є порядокBy чи фільтр у вашій ng-повторенні
Джоан-Дієго Родрігес

Це буде краще, якщо ви використовували трек за $ index
Анкіт Балян

@ Джоан-DiegoRodriguez Як би ви отримаєте його на роботу , якщо у вас є фільтр / OrderBy Ніколи не заперечує тільки що прочитали XMLilley в відповідь
jamesmstone

26

Якщо ви знаходитесь у ng-повторі

ви можете використовувати один варіант вкладиша

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

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

$index використовується кутовим для відображення поточного індексу масиву всередині ng-repeat


1
Мені подобається і використовував цей один лайнер
etoricky

24

Використання $indexпрацює чудово в основних випадках, і відповідь @ charlietfl чудова. Але іноді $indexнедостатньо.

Уявіть, що у вас є один масив, який ви представляєте у двох різних ng-повторах. Один з цих ng-повторів фільтрується для об'єктів, які мають властивість truthy, а інший фільтрується за хибною властивістю. Представлено два різних відфільтрованих масиви, які походять від одного вихідного масиву. (Або якщо це допомагає візуалізувати: можливо, у вас є один масив людей, і ви хочете один ng-повторення для жінок у цьому масиві, а інший для чоловіків у тому ж масиві .) Ваша мета: надійно видалити з оригінальний масив, використовуючи інформацію від членів відфільтрованих масивів.

У кожному з цих відфільтрованих масивів $ index не буде індексом елемента в початковому масиві. Це буде індекс у відфільтрованому підмасиві . Отже, ви не зможете вказати індекс людини в початковому peopleмасиві, ви будете знати лише індекс $ з масиву womenабо menпідмасиву. Спробуйте видалити за допомогою цього, і у вас зникнуть предмети звідусіль, окрім того, де ви хотіли. Що робити?

Якщо вам пощастило, що використання моделі даних включає в себе унікальний ідентифікатор для кожного об'єкта, тоді використовуйте це замість $ index, щоб знайти об'єкт і spliceйого з головного масиву. (Використовуйте мій приклад нижче, але з цим унікальним ідентифікатором.) Але якщо вам не так пощастило?

Angular насправді збільшує кожен елемент у ng-повторюваному масиві (в основному, оригінальному масиві) з унікальною властивістю, що називається $$hashKey. Ви можете шукати оригінальний масив на відповідність $$hashKeyелементу, який ви хочете видалити, і позбутися його таким чином.

Зауважте, що $$hashKeyце детальна інформація про реалізацію, не включена до опублікованого API для 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;
    };
  });
}

Надіслати:

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

РЕДАКТУВАННЯ: Використання такої функції, яка натискає $$hashKeyзамість назви властивості, що відповідає конкретній моделі, також має значну додаткову перевагу - зробити цю функцію багаторазовою для використання в різних моделях та контекстах. Надайте його своїм посиланням на масив та посиланням на ваш елемент, і він повинен просто працювати.


10

Я зазвичай пишу в такому стилі:

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


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

Сподіваюсь, це допоможе Вам використовувати точку (.) Між $ range та [yourArray]


Яке значення "1" у (індекс, 1)
ShibinRagh

@ShibinRagh Це те deleteCount. Ціле число, що вказує кількість старих елементів масиву для видалення. Якщо deleteCount дорівнює 0, жодні елементи не видаляються. У цьому випадку слід вказати хоча б один новий елемент. Якщо deleteCount перевищує кількість елементів, залишених у масиві, починаючи з початку, то всі елементи через кінець масиву будуть видалені. Array.prototype.splice () Документація
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

9

Грунтуючись на загальноприйнятому відповідь, це буде працювати з ngRepeat, filterі ручки краще очікуваннях:

Контролер:

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

Вид:

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

Ви не призначили в "контролері" "видалити" на $ range.vm свого контролера, тому цей код не працює. Тепер, якщо ви зробили це ... $ range.vm = {delete: function () {...}}, то це було б.
Джастін Руссо

4

реалізація без контролера.

<!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>

Метод splice () додає / видаляє елементи з / з масиву.

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

індекс : Обов’язково. Ціле число, яке вказує, в яку позицію додавати / видаляти елементи, Використовуйте негативні значення, щоб вказати позицію з кінця масиву.

howmanyitem (s) : Необов’язково. Кількість елементів, які потрібно вилучити. Якщо встановлено 0, жоден елемент не буде видалений.

item_1, ..., item_n : Необов’язково. Новий елемент, який потрібно додати до масиву


1
Це правильна відповідь. Навіщо покладатися на контролер для здійснення простих дзвінків JavaScript?
Elle Fie

3

Я не погоджуюся, що вам слід викликати метод на контролері. Вам слід використовувати сервіс для будь-якого фактичного функціонування, і ви повинні визначати директиви для будь-якої функціональності щодо масштабованості та модульності, а також призначати подію натискання, яка містить виклик службі, яку ви вводите у свою директиву.

Так, наприклад, у вашому HTML ...

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

Потім створіть директиву ...

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

Тоді до ваших послуг ...

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

Коли ви правильно пишете свій код таким чином, ви будете дуже легко писати майбутні зміни, не потребуючи реструктуризації коду. Він організований належним чином, і ви обробляєте власні події клацань правильно, прив’язуючи користувальницькі директиви.

Наприклад, якщо ваш клієнт каже: "Ей, тепер давайте змусимо його зателефонувати на сервер і заробити хліб, а потім спливати модальний". Ви зможете легко перейти до самої послуги, не потребуючи додавання чи зміни будь-якого коду HTML та / або контролера. Якщо у вас був лише один рядок на контролері, вам, зрештою, потрібно буде скористатися послугою для розширення функціональності до більш важкого підйому, про який вимагає клієнт.

Крім того, якщо вам потрібна інша кнопка "Видалити" в іншому місці, тепер у вас є атрибут директиви ("ng-remove-birthday"), який ви можете легко призначити будь-якому елементу на сторінці. Це робить його модульним і багаторазовим. Це стане в нагоді під час роботи з HEADY парадигмою веб-компонентів Angular 2.0. У 2.0 немає контролера. :)

Щасливого розвитку !!!


1

Ось ще одна відповідь. Сподіваюся, це допоможе.

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

$scope.delete(item){
 var index = this.list.indexOf(item);
                this.list.splice(index, 1);   
}

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

Повне джерело тут
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice


0

якщо у вашому елементі є ідентифікатор або якесь певне поле, ви можете скористатися filter (). її вчинок, як і де ().

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

в контролері:

$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 

від контролера (Функція може бути в тому ж контролері, але вважають за краще тримати його в сервісі)

    function removeInfo(id) {
    let item = bdays.filter(function(item) {
      return bdays.id=== id;
    })[0];
    let index = bdays.indexOf(item);
    data.device.splice(indexOfTabDetails, 1);
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.