Как удалить элемент из массива в области видимости AngularJS?

153

Простой список дел, но с кнопкой удаления на странице списка для каждого элемента:

введите описание изображения здесь

Соответствующий шаблон HTML:

<tr ng-repeat="person in persons">
  <td>{{person.name}} - # {{person.id}}</td>
  <td>{{person.description}}</td>
  <td nowrap=nowrap>
    <a href="#!/edit"><i class="icon-edit"></i></a>
    <button ng-click="delete(person)"><i class="icon-minus-sign"></i></button>
  </td>
</tr>

Соответствующий метод контроллера:

$scope.delete = function (person) {
  API.DeletePerson({ id: person.id }, function (success) {
    // I need some code here to pull the person from my scope.
  });
};

Я попробовал $scope.persons.pull(person)и $scope.persons.remove(person).

Хотя база данных успешно удалена, я не могу вытащить этот элемент из области и не хочу вызывать метод на сервере для данных, которые уже есть у клиента, я просто хочу удалить этого человека из области.

Любые идеи?

до свидания
источник
Я бегу по этому маршруту, и вид не будет работать нормально. Я всегда получал пустую страницу после удаления :-(
zx1986
Выписали подобную статью codepedia.info/angularjs-delete-table-row-tr-on-click
Сатиндер Singh
речь идет не столько об удалении из области видимости, сколько из массива, и это будет то же самое независимо от
угла

Ответы:

259

Ваша проблема не в Angular, а в методах Array. Правильный способ удалить конкретный элемент из массиваArray.splice . Также при использовании ng-repeat у вас есть доступ к$index свойству, которое является текущим индексом массива, который вы передали.

Решение на самом деле довольно простое:

Посмотреть:

<a ng-click="delete($index)">Delete</a>

контроллер:

$scope.delete = function ( idx ) {
  var person_to_delete = $scope.persons[idx];

  API.DeletePerson({ id: person_to_delete.id }, function (success) {
    $scope.persons.splice(idx, 1);
  });
};
Джош Дэвид Миллер
источник
1
@ ScottMalachowski Ты прав. Я забыл эту часть. Я пересмотрел свой ответ, чтобы отразить это, поэтому он будет соответствовать вашему.
Джош Дэвид Миллер
13
Осторожно - это решение на основе индекса не будет работать, если вы используете несколько ng-повторов одного и того же объекта в представлении (например, запланированные задачи, незапланированные задачи, выполненные задачи, все выходящие из $ scope.tasks), поскольку у вас будет несколько элементов с указатель 2, 3, 4 и т. д.
шейкер
Приведенный выше комментарий @shacker о нескольких ng-повторах с различными отфильтрованными наборами одного и того же массива является правильным. Используйте метод ниже с indexOf
Эндрю Куклевич
4
@AndrewKuklewicz - indexOfможет быть более дорогой операцией; без фильтрации это совершенно не нужно. Но с фильтрацией, indexOfбудет соответствующий метод.
Джош Дэвид Миллер
Я борюсь с этим и должен был внести небольшие изменения в генерацию тега выше - будучи - удалить ({{$ index}}) с помощью {{}} в противном случае я получил строку $ index - НО у меня что-то не так, потому что это никогда не вызывает этот метод. Это происходит, когда я удаляю упоминание индекса, например delete (), но это не очень помогает.
mikemil
310

Вам нужно будет найти индекс personв вашем personsмассиве, а затем использовать метод массива splice:

$scope.persons.splice( $scope.persons.indexOf(person), 1 );
Джозеф Силбер
источник
49
это лучший ответ; работает, когда список был отфильтрован, поэтому индекс в представлении не совпадает с индексом в области видимости.
Эндрю Куклевич
5
Это действительно лучший ответ. Обратите внимание, что в дополнение к варианту использования отфильтрованных списков, упомянутому Эндрю, этот подход также охватывает случай, когда вы удаляете несколько человек, и запросы Ajax для этих удалений возвращаются не в порядке. Если вы использовали индексы строк до возврата вызова Ajax, вы в конечном итоге удалите неправильные строки.
Йорис
4
В некоторых случаях лучше, но с indexOf вам нужно перебирать все элементы, чтобы найти правильный, в ответе Джоша вы получаете индекс и элемент быстрее
daver
@mike - используйте этот полифилл .
Джозеф Сильбер
8

Я бы использовал библиотеку Underscore.js, в которой есть список полезных функций.

without

without_.without(array, *values)

Возвращает копию массива со всеми удаленными экземплярами значений.

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
// => [2, 3, 4]

пример

var res = "deleteMe";

$scope.nodes = [
  {
    name: "Node-1-1"
  },
  {
    name: "Node-1-2"
  },
  {
    name: "deleteMe"
  }
];
    
$scope.newNodes = _.without($scope.nodes, _.findWhere($scope.nodes, {
  name: res
}));

Смотрите Демо в JSFiddle .


filter

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });

// => [2, 4, 6]

пример

$scope.newNodes = _.filter($scope.nodes, function(node) {
  return !(node.name == res);
});

Смотрите Демо в Fiddle .

Максим Шустин
источник
Я бы, вероятно, использовал, $scope.nodes = _.without($scope.nodes, node);потому что у него есть ссылка наnode
Джейк
В современных браузерах вы можете использовать Array.prototype.filter. _.filter(array, fun)становится array.filter(fun).
bfontaine
7
$scope.removeItem = function() {
    $scope.items.splice($scope.toRemove, 1);
    $scope.toRemove = null;
};

это работает для меня!

cebor
источник
4

Если у вас есть какая-либо функция, связанная со списком, при создании функции сращивания также удаляется ассоциация. Мое решение:

$scope.remove = function() {
    var oldList = $scope.items;
    $scope.items = [];

    angular.forEach(oldList, function(x) {
        if (! x.done) $scope.items.push( { [ DATA OF EACH ITEM USING oldList(x) ] });
    });
};

Список параметров именованных предметов . Параметр x.done указывает, будет ли элемент удален.

Другие ссылки: Другой пример

Надеюсь, вам поможет. Приветствую.

Drako
источник
2

Для принятого ответа @Joseph Silber не работает, потому что indexOf возвращает -1. Вероятно, это связано с тем, что Angular добавляет хеш-ключ, который отличается для моего $ scope.items [0] и моего элемента. Я попытался решить эту проблему с помощью функции angular.toJson (), но она не сработала :(

Ах, я выяснил причину ... Я использую метод чанка для создания двух столбцов в моей таблице, просматривая мои $ scope.items. Сожалею!

gabn88
источник
2

Вы также можете использовать это

$scope.persons = $filter('filter')($scope.persons , { id: ('!' + person.id) });
Chetann
источник
1

Angular имеет встроенную функцию под названием arrayRemove, в вашем случае метод может быть просто:

arrayRemove($scope.persons, person)
Аллен
источник