[angularjs] How to remove elements/nodes from angular.js array

I am trying to remove elements from the array $scope.items so that items are removed in the view ng-repeat="item in items"

Just for demonstrative purposes here is some code:

for(i=0;i<$scope.items.length;i++){
    if($scope.items[i].name == 'ted'){
      $scope.items.shift();
    }
}

I want to remove the 1st element from the view if there is the name ted right? It works fine, but the view reloads all the elements. Because all the array keys have shifted. This is creating unnecessary lag in the mobile app I am creating..

Anyone have an solutions to this problem?

This question is related to angularjs scope angularjs-ng-repeat

The answer is


My solution was quite straight forward

app.controller('TaskController', function($scope) {
 $scope.items = tasks;

    $scope.addTask = function(task) {
        task.created = Date.now();
        $scope.items.push(task);
        console.log($scope.items);
    };

    $scope.removeItem = function(item) {
        // item is the index value which is obtained using $index in ng-repeat
        $scope.items.splice(item, 1);
    }
});

Here is filter with Underscore library might help you, we remove item with name "ted"

$scope.items = _.filter($scope.items, function(item) {
    return !(item.name == 'ted');
 });

For anyone returning to this question. The correct "Angular Way" to remove items from an array is with $filter. Just inject $filter into your controller and do the following:

$scope.items = $filter('filter')($scope.items, {name: '!ted'})

You don't need to load any additional libraries or resort to Javascript primitives.


I liked the solution provided by @madhead

However the problem I had is that it wouldn't work for a sorted list so instead of passing the index to the delete function I passed the item and then got the index via indexof

e.g.:

var index = $scope.items.indexOf(item);
$scope.items.splice(index, 1);

An updated version of madheads example is below: link to example

HTML

<!DOCTYPE html>
<html data-ng-app="demo">
  <head>
    <script data-require="[email protected]" data-semver="1.1.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>
  <body>
    <div data-ng-controller="DemoController">
      <ul>
        <li data-ng-repeat="item in items|orderBy:'toString()'">
          {{item}}
          <button data-ng-click="removeItem(item)">Remove</button>
        </li>
      </ul>
      <input data-ng-model="newItem"><button data-ng-click="addItem(newItem)">Add</button>
    </div>
  </body>
</html>

JavaScript

"use strict";

var demo = angular.module("demo", []);

function DemoController($scope){
  $scope.items = [
    "potatoes",
    "tomatoes",
    "flour",
    "sugar",
    "salt"
  ];

  $scope.addItem = function(item){
    $scope.items.push(item);
    $scope.newItem = null;
  }

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

You can use plain javascript - Array.prototype.filter()

$scope.items = $scope.items.filter(function(item) {
    return item.name !== 'ted';
});

Using the indexOf function was not cutting it on my collection of REST resources.

I had to create a function that retrieves the array index of a resource sitting in a collection of resources:

factory.getResourceIndex = function(resources, resource) {
  var index = -1;
  for (var i = 0; i < resources.length; i++) {
    if (resources[i].id == resource.id) {
      index = i;
    }
  }
  return index;
}

$scope.unassignedTeams.splice(CommonService.getResourceIndex($scope.unassignedTeams, data), 1);

My solution to this (which hasn't caused any performance issues):

  1. Extend the array object with a method remove (i'm sure you will need it more than just one time):
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

I'm using it in all of my projects and credits go to John Resig John Resig's Site

  1. Using forEach and a basic check:
$scope.items.forEach(function(element, index, array){
          if(element.name === 'ted'){
              $scope.items.remove(index);
          }
        });

At the end the $digest will be fired in angularjs and my UI is updated immediately without any recognizable lag.


My items have unique id's. I am deleting one by filtering the model with angulars $filter service:

var myModel = [{id:12345, ...},{},{},...,{}];
...
// working within the item
function doSthWithItem(item){
... 
  myModel = $filter('filter')(myModel, function(value, index) 
    {return value.id !== item.id;}
  );
}

As id you could also use the $$hashKey property of your model items: $$hashKey:"object:91"


Just a slight expansion on the 'angular' solution. I wanted to exclude an item based on it's numeric id, so the ! approach doesn't work. The more general solution which should work for { name: 'ted' } or { id: 42 } is:

mycollection = $filter('filter')(myCollection, { id: theId }, function (obj, test) { 
                                                             return obj !== test; });

Because when you do shift() on an array, it changes the length of the array. So the for loop will be messed up. You can loop through from end to front to avoid this problem.

Btw, I assume you try to remove the element at the position i rather than the first element of the array. ($scope.items.shift(); in your code will remove the first element of the array)

for(var i = $scope.items.length - 1; i >= 0; i--){
    if($scope.items[i].name == 'ted'){
        $scope.items.splice(i,1);
    }
}

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. Hope help you. Greetings.


Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to scope

Angular 2 - Using 'this' inside setTimeout Why Is `Export Default Const` invalid? How do I access previous promise results in a .then() chain? Problems with local variable scope. How to solve it? Why is it OK to return a 'vector' from a function? Uncaught TypeError: Cannot read property 'length' of undefined Setting dynamic scope variables in AngularJs - scope.<some_string> How to remove elements/nodes from angular.js array Limiting number of displayed results when using ngRepeat A variable modified inside a while loop is not remembered

Examples related to angularjs-ng-repeat

Angular ng-repeat add bootstrap row every 3 or 4 cols ng-if, not equal to? Understanding the ngRepeat 'track by' expression Calculating sum of repeated elements in AngularJS ng-repeat Angular.js ng-repeat filter by property having one of multiple values (OR of values) Using ng-if as a switch inside ng-repeat? In Angular, how to pass JSON object/array into directive? how to split the ng-repeat data with three columns using bootstrap Preserve line breaks in angularjs ng-repeat: access key and value for each object in array of objects