154

Simple to-do list, but with a delete button on list page for each item:

enter image description here

Relevant template 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>

Relevant controller method:

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

I tried $scope.persons.pull(person) and $scope.persons.remove(person).

Although the database deleted successfully, I can not pull this item from scope and I do not want to make a method call to the server for data the client already has, I just want to remove this one person from scope.

Any ideas?

2
  • I run this whit $route, and the view won't work fine. I always got a empty page after I did the delete :-( Commented Sep 4, 2013 at 11:43
  • this is not so much about deleting from scope but rather from an array, and it would be the same regardless of angular, its just javascript Commented May 14, 2020 at 10:17

10 Answers 10

309

You'll have to find the index of the person in your persons array, then use the array's splice method:

$scope.persons.splice( $scope.persons.indexOf(person), 1 );
Sign up to request clarification or add additional context in comments.

4 Comments

this is a better answer; works when the list has been filtered so that that index in the view is not the same as in the array in scope.
This is indeed the better answer. Note that in addition to the filtered lists use case mentioned by Andrew, this approach also covers the case in which you delete multiple persons and the Ajax requests for these deletes return out of order. If you have use the row indexes from before the Ajax call return, you'll end up removing the wrong rows.
Is better in some cases, but with indexOf you have to iterate over all the items to find the right one, in the Josh answer you get the index and the item faster
@mike - Use this polyfill.
260

Your issue is not really with Angular, but with Array methods. The proper way to remove a particularly item from an array is with Array.splice. Also, when using ng-repeat, you have access to the special $index property, which is the current index of the array you passed in.

The solution is actually pretty straightforward:

View:

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

Controller:

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

8 Comments

@ScottMalachowski You're right. I forgot that part. I revised my answer to reflect that, so it'll be consistent with yours.
Careful - this index-based solution will not work if you use multiple ng-repeats of the same object in a view (e.g. Scheduled Tasks, Unscheduled Tasks, Completed Tasks all coming out of $scope.tasks) because you will have multiple items with index 2, 3, 4, etc.
Comment above, by @shacker, about multiple ng-repeats with different filtered sets of the same array, is right on. Use method below with indexOf
@AndrewKuklewicz - indexOf can be a more expensive operation; without filtering, it's completely unnecessary. But with filtering, indexOf would be the appropriate method.
I am struggling with this and had to make a minor change to the tag generation above - being - delete({{$index}}) with the {{ }} otherwise I got the string $index - BUT I have something wrong because it never calls that method. It does when I remove any mention of the index like delete() but that doesn't really help.
|
8

I would use the Underscore.js library that has a list of useful functions.

without

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]

Example

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]

Example

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

See Demo in Fiddle.

2 Comments

I'd probably use $scope.nodes = _.without($scope.nodes, node); because he has reference to the node
On modern browsers you can use Array.prototype.filter. _.filter(array, fun) becomes array.filter(fun).
7
$scope.removeItem = function() {
    $scope.items.splice($scope.toRemove, 1);
    $scope.toRemove = null;
};

this works for me!

Comments

4

If you have any function associated to list ,when you make the splice function, the association is deleted too. My solution:

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

The list param is named items. The param x.done indicate if the item will be deleted.

Another references: Another example

Hope help you. Greetings.

Comments

2

For the the accepted answer of @Joseph Silber is not working, because indexOf returns -1. This is probably because Angular adds an hashkey, which is different for my $scope.items[0] and my item. I tried to resolve this with the angular.toJson() function, but it did not work :(

Ah, I found out the reason... I use a chunk method to create two columns in my table by watching my $scope.items. Sorry!

Comments

2

You can also use this

$scope.persons = $filter('filter')($scope.persons , { id: ('!' + person.id) });

Comments

1

Angular have a built-in function called arrayRemove, in your case the method can simply be:

arrayRemove($scope.persons, person)

Comments

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

Comments

0

To remove a element from scope use:

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

From enter link description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.