¿Cómo eliminar un elemento de una matriz en el alcance de AngularJS?

153

Lista de tareas simple, pero con un botón Eliminar en la página de lista para cada elemento:

ingrese la descripción de la imagen aquí

HTML de plantilla relevante:

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

Método de controlador relevante:

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

Lo intenté $scope.persons.pull(person)y $scope.persons.remove(person).

Aunque la base de datos se eliminó con éxito, no puedo extraer este elemento del alcance y no quiero hacer una llamada al método para el servidor para los datos que el cliente ya tiene, solo quiero eliminar a esta persona del alcance.

¿Algunas ideas?

Adiós
fuente
Ejecuto esto con $ route, y la vista no funcionará bien. Siempre tengo una página vacía después de borrar :-(
zx1986
Han escrito un artículo similar codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh
no se trata tanto de eliminar del alcance sino de una matriz, y sería lo mismo independientemente de angular, es solo javascript
Xsmael

Respuestas:

259

Su problema no es realmente con Angular, sino con los métodos de matriz. La forma correcta de eliminar un elemento particular de una matriz es con Array.splice. Además, cuando usa ng-repeat, tiene acceso a la $indexpropiedad especial , que es el índice actual de la matriz que pasó.

La solución es bastante sencilla:

Ver:

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

Controlador:

$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);
  });
};
Josh David Miller
fuente
1
@ScottMalachowski Tienes razón. Olvidé esa parte. Revisé mi respuesta para reflejar eso, por lo que será coherente con la suya.
Josh David Miller
13
Cuidado: esta solución basada en índices no funcionará si usa varias repeticiones ng del mismo objeto en una vista (por ejemplo, Tareas programadas, Tareas no programadas, Tareas completadas que salen de $ scope.tasks) porque tendrá varios elementos con índice 2, 3, 4, etc.
shacker
El comentario anterior, de @shacker, acerca de múltiples repeticiones ng con diferentes conjuntos filtrados de la misma matriz, es correcto. Utilice el siguiente método con indexOf
Andrew Kuklewicz
44
@AndrewKuklewicz: indexOfpuede ser una operación más costosa; sin filtrado, es completamente innecesario. Pero con el filtrado, indexOfsería el método apropiado.
Josh David Miller
Estoy luchando con esto y tuve que hacer un pequeño cambio en la generación de etiquetas anterior: ser - eliminar ({{$ index}}) con {{}} de lo contrario obtuve la cadena $ index, PERO tengo algo mal porque Nunca llama a ese método. Lo hace cuando elimino cualquier mención del índice como delete () pero eso realmente no ayuda.
mikemil
310

Tendrá que encontrar el índice de personen su personsmatriz, luego use el splicemétodo de la matriz :

$scope.persons.splice( $scope.persons.indexOf(person), 1 );
Joseph Silber
fuente
49
esta es una mejor respuesta; funciona cuando la lista se ha filtrado para que ese índice en la vista no sea el mismo que en la matriz en el alcance.
Andrew Kuklewicz
55
Esta es de hecho la mejor respuesta. Tenga en cuenta que, además del caso de uso de listas filtradas mencionado por Andrew, este enfoque también cubre el caso en el que elimina a varias personas y las solicitudes de Ajax para estas eliminaciones se devuelven fuera de servicio. Si ha utilizado los índices de fila anteriores a la devolución de la llamada Ajax, terminará eliminando las filas incorrectas.
Joris
44
Es mejor en algunos casos, pero con indexOf tienes que iterar sobre todos los elementos para encontrar el correcto, en la respuesta de Josh obtienes el índice y el elemento más rápido
daver el
@mike: usa este polyfill .
Joseph Silber
8

Me gustaría utilizar el Underscore.js biblioteca que tiene una lista de funciones útiles.

without

without_.without(array, *values)

Devuelve una copia de la matriz con todas las instancias de los valores eliminados.

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

Ejemplo

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

Ver demostración en JSFiddle .


filter

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

// => [2, 4, 6]

Ejemplo

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

Ver demostración en Fiddle .

Maxim Shoustin
fuente
Probablemente lo usaría $scope.nodes = _.without($scope.nodes, node);porque tiene referencia a lanode
jake
En los navegadores modernos que puede usar Array.prototype.filter. _.filter(array, fun)se convierte array.filter(fun).
bfontaine
7
$scope.removeItem = function() {
    $scope.items.splice($scope.toRemove, 1);
    $scope.toRemove = null;
};

esto funciona para mi!

cebor
fuente
4

Si tiene alguna función asociada a la lista, cuando realiza la función de empalme, la asociación también se elimina. Mi solución:

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

El parámetro de la lista se denomina elementos . El parámetro x.done indica si el elemento se eliminará.

Otras referencias: otro ejemplo

Espero ayudarte. Saludos.

Drako
fuente
2

Para la respuesta aceptada de @Joseph Silber no funciona, porque indexOf devuelve -1. Esto probablemente se deba a que Angular agrega un hashkey, que es diferente para mi $ scope.items [0] y mi artículo. Traté de resolver esto con la función angular.toJson (), pero no funcionó :(

Ah, descubrí la razón ... Utilizo un método fragmentado para crear dos columnas en mi tabla mirando mis $ scope.items. ¡Lo siento!

gabn88
fuente
2

También puedes usar esto

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

Angular tiene una función incorporada llamada arrayRemove, en su caso, el método puede ser simplemente:

arrayRemove($scope.persons, person)
Allen
fuente
1
array.splice(array.pop(item));
Taran
fuente