如何在AngularJS作用域中从数组中删除一个项目?

154

简单的待办事项清单,但列表页面上每个项目都带有一个删除按钮:

输入图像描述

相关模板 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)

虽然数据库已经成功删除,但是我无法从作用域中拉取这个项目,并且我不想调用服务器上已经存在的客户端数据的方法,我只想从作用域中删除这一个人。

有什么想法吗?


我使用$route运行此程序,但视图无法正常工作。在执行删除操作后,我总是得到一个空白页面 :-( - zx1986
这并不是关于从作用域中删除,而是从数组中删除,无论是在Angular中还是在JavaScript中都是一样的。 - Xsmael
10个回答

310

你需要在 persons 数组中找到 person 的索引,然后使用该数组的 splice 方法:

$scope.persons.splice( $scope.persons.indexOf(person), 1 );

49
这是一个更好的答案;当列表已被过滤以使视图中的索引与作用域中的数组不相同时,它可以运行。 - Andrew Kuklewicz
5
这确实是更好的答案。请注意,除了Andrew提到的过滤列表用例之外,这种方法还涵盖了删除多个人并且这些删除的Ajax请求返回顺序混乱的情况。如果您使用之前Ajax调用返回的行索引进行删除,那么最终会删除错误的行。 - Joris
4
在某些情况下,使用其他方法可能更好,但是如果使用indexOf方法,你需要迭代所有项目才能找到正确的一个。而在Josh的答案中,你可以更快地获取索引和相应的项。 - daver
@mike - 使用这个polyfill - Joseph Silber

260
你的问题实际上不是与Angular有关,而是与数组方法有关。从数组中删除特定项的正确方法是使用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 你说得对。我忘记了那部分内容。我修改了我的答案以反映这一点,这样它就与你的答案保持一致。 - Josh David Miller
13
注意 - 如果在视图中使用同一对象的多个ng-repeats(例如,Scheduled Tasks,Unscheduled Tasks,Completed Tasks都来自$scope.tasks),则基于索引的此解决方案将无效,因为您将具有多个索引为2、3、4等的项目。 - shacker
4
indexOf这个方法的执行成本比较高;如果没有筛选条件,使用它就完全没有必要。但是如果有筛选条件,那么indexOf就是合适的方法。 - Josh David Miller
我在这个问题上遇到了困难,不得不对上面的标签生成进行了一点小改动 - 即删除({{$index}})中的{{ }},否则我得到的是字符串$index - 但是我做错了什么,因为它从来没有调用那个方法。当我删除任何关于索引的提及时,比如delete(),它确实会调用,但这并没有真正帮助到我。 - mikemil
@mikemil 什么标签生成?你有一个 plunker 吗? - Josh David Miller
显示剩余3条评论

8

我会使用 Underscore.js 库,它有许多有用的函数。

without

without 函数是 Underscore.js 库中的一个函数。

without_.without(array, *values)

Returns a copy of the array with all instances of the values removed.

_.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
}));

See Demo in 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);,因为他已经有该节点的引用。 - jake
在现代浏览器上,您可以使用Array.prototype.filter_.filter(array, fun)变成了array.filter(fun) - bfontaine

7
$scope.removeItem = function() {
    $scope.items.splice($scope.toRemove, 1);
    $scope.toRemove = null;
};

这对我来说有效!


4
如果您与列表相关的任何函数,当您执行splice功能时,相关联的功能也将被删除。我的解决方案:
$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) ] });
    });
};
  • 列表参数被命名为items
  • 参数x.done表示该项是否将被删除。

其他参考:另一个示例

希望能帮到您。问候。


2
你可以使用这个。
$scope.persons = $filter('filter')($scope.persons , { id: ('!' + person.id) });

2

@Joseph Silber提供的答案不可行,因为indexOf返回-1。这可能是因为Angular添加了一个哈希键,它对我的$scope.items [0]和我的item是不同的。我尝试使用angular.toJson()函数来解决这个问题,但它没有起作用:(

啊,我找到原因了...我使用了一个chunk方法来通过观察我的$scope.items在我的表格中创建两列。对不起!


1

Angular有一个内置函数叫做arrayRemove,在你的情况下,该方法可以简单地为:

arrayRemove($scope.persons, person)

1
array.splice(array.pop(item));

0

要从作用域中删除元素,请使用:

// remove an item
    $scope.remove = function(index) {
        $scope.items.splice(index, 1);
    };

在此输入链接描述


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接