Как удалить элемент или объект из массива с помощью ng-click?

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-repeat я обновил вопрос
Джесс Маккензи
Вот моя 1 статья, в которой объясняется, как удалить запись с помощью ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
singh

Ответы:

552

Чтобы удалить элемент, вам нужно удалить его из массива и передать 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);     
}

Angular автоматически обнаружит изменение в bdaysмассиве и выполнит обновлениеng-repeat

ДЕМО: http://plnkr.co/edit/ZdShIA?p=preview

РЕДАКТИРОВАТЬ: Если для выполнения прямых обновлений с сервером будет использоваться служба, которую вы создаете, $resourceчтобы управлять обновлениями массива одновременно с сервером обновлений

charlietfl
источник
62
Использование $indexнапрямую может генерировать ошибки, если ваш список фильтруется по шаблону. Это шаблонная вещь; безопаснее использования ng-click='remove(bday)'затемarr.splice(arr.indexOf(bday),1);
Umur Kontacı
6
Вам не нужно передавать $ index, потому что вы можете использовать «this» внутри метода. $ scope.remove = function () {$ scope.bdays.splice (this. $ 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 +
Леви
17
Это не сработает, если у вас есть orderBy или фильтр в вашем ng-repeat
Джоан-Диего Родригес
Это будет работать лучше, если вы использовали трек по $ index
Анкит Балян
@ Joan-DiegoRodriguez Как вы можете заставить его работать, если у вас есть фильтр / заказ? Не берите в голову, просто прочитайте Ответ
XMLilley
26

Если вы находитесь внутри ng-repeat

Вы могли бы использовать один вариант лайнера

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

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

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

azerafati
источник
1
Я люблю и использовал этот лайнер
etoricky
24

Использование $indexотлично работает в основных случаях, и ответ @ charlietfl великолепен. Но иногда $indexэтого недостаточно.

Представьте, что у вас есть один массив, который вы представляете в двух разных ng-repeat. Один из этих ng-repeat фильтруется для объектов, имеющих свойство truey, а другой - для свойства false. Представлены два разных отфильтрованных массива, которые происходят из одного исходного массива. (Или, если это помогает визуализировать: возможно, у вас есть один массив людей, и вам нужно одно ng-повторение для женщин в этом массиве и другое для мужчин в этом же массиве .) Ваша цель: надежно удалить из исходный массив, использующий информацию от членов отфильтрованных массивов.

В каждом из этих отфильтрованных массивов $ index не будет индексом элемента в исходном массиве. Это будет индекс в отфильтрованном подмассиве . Таким образом, вы не сможете узнать индекс человека в исходном peopleмассиве, вы будете знать только индекс $ из подмассива womenили men. Попробуйте удалить, используя это, и у вас будут предметы, исчезающие отовсюду, за исключением того, что вы хотели. Что делать?

Если вам повезло, вы используете модель данных, содержащую уникальный идентификатор для каждого объекта, а затем используйте его вместо $ index, чтобы найти объект и spliceего значение вне основного массива. (Используйте мой пример ниже, но с этим уникальным идентификатором.) Но если вам не так повезло?

Angular фактически увеличивает каждый элемент в массиве с повторением ng (в основном, исходном массиве) уникальным свойством, которое называется $$hashKey. Вы можете найти в исходном массиве совпадение с $$hashKeyэлементом, который хотите удалить, и таким образом избавиться от него.

Обратите внимание, что $$hashKeyэто деталь реализации, не включенная в опубликованный API для ng-repeat. Они могут удалить поддержку этого свойства в любое время. Но, вероятно, нет. :-)

$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вместо имени специфичного для модели ключа используется ключ , также имеет существенное дополнительное преимущество, заключающееся в возможности многократного использования этой функции в различных моделях и контекстах. Укажите в нем ссылку на массив и ссылку на элемент, и она должна просто работать.

XML
источник
10

Я обычно пишу в таком стиле:

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


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

Надеюсь, что это поможет Вам использовать точку (.) Между $ scope и [yourArray]

Святослав Новосядлый
источник
Что означает «1» в (индекс, 1)
ShibinRagh
@ShibinRagh Это deleteCount . Целое число, указывающее количество удаляемых старых элементов массива. Если deleteCount равен 0, элементы не удаляются. В этом случае вы должны указать хотя бы один новый элемент. Если deleteCount больше, чем количество элементов, оставшихся в массиве, начиная с начала, то все элементы до конца массива будут удалены. Array.prototype.splice () Документация
ʙᴀᴋᴇʀ '13
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)"
Джоан-Диего Родригес
источник
В вашем контроллере вы не назначали «remove» для $ scope.vm, поэтому этот код не будет работать. Теперь, если вы сделали это ... $ scope.vm = {remove: 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

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

Так, например, на вашем 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»), который вы можете легко назначить любому элементу на странице. Это теперь делает его модульным и многоразовым. Это пригодится при работе с парадигмой веб-компонентов HEAVY в 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);
  }
Уткарш Джоши
источник