¿Cómo elimino un elemento u objeto de una matriz usando ng-click?

261

Estoy tratando de escribir una función que me permita eliminar un elemento cuando se hace clic en el botón, pero creo que me estoy confundiendo con la función: ¿lo uso $digest?

HTML y app.js:

<ul ng-repeat="bday in bdays">
  <li>
    <span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
    <form ng-show="editing" ng-submit="editing = false">
      <label>Name:</label>
      <input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
      <label>Date:</label>
      <input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
      <br/>
      <button class="btn" type="submit">Save</button>
      <a class="btn" ng-click="remove()">Delete</a>
    </form>
  </li>
</ul>

$scope.remove = function(){
  $scope.newBirthday = $scope.$digest();
};
Jess McKenzie
fuente
2
No desea $ digest, ya que se usa para ingresar al bucle de resumen de Angular (y ya está en un bucle de resumen debido al ng-clic). ¿Estás tratando de eliminar un elemento de una matriz?
Mark Rajcok
@MarkRajcok :) sí, eso es lo que estoy tratando de hacer
Jess McKenzie
remove()en ng-clickla forma en que lo tienes no tiene contexto. Necesita más detalles en el marcado para mostrar qué se está eliminando y si está dentro ng-repeat, o de dónde proviene el elemento que se está eliminando, o qué comportamiento desearemove()
charlietfl
@charlietfl está dentro de ng-repeat He actualizado la pregunta
Jess McKenzie
Aquí está mi 1 artículo que explica cómo eliminar registros con ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh

Respuestas:

552

Para eliminar el elemento, debe eliminarlo de la matriz y puede pasar el bdayelemento a su función de eliminación en el marcado. Luego, en el controlador, busque el índice del elemento y retírelo de la matriz

<a class="btn" ng-click="remove(item)">Delete</a>

Luego en el controlador:

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

Angular detectará automáticamente el cambio en la bdaysmatriz y realizará la actualización deng-repeat

DEMO: http://plnkr.co/edit/ZdShIA?p=preview

EDITAR: si realizar actualizaciones en vivo con el servidor usaría un servicio que usted cree $resourcepara administrar las actualizaciones de la matriz al mismo tiempo que actualiza el servidor

charlietfl
fuente
62
El uso $indexdirecto puede generar errores si su lista se filtra en la plantilla. Es una cosa de plantilla; es más seguro de usar ng-click='remove(bday)'entoncesarr.splice(arr.indexOf(bday),1);
Umur Kontacı
66
No necesita pasar $ index porque puede usar 'this' dentro del método. $ scope.remove = function () {$ scope.bdays.splice (this. $ index, 1); }
matchdav
1
@matthewdavidson this is undefined. ¿Plunker / jsfiddle quizás?
Tjorriemorrie
11
.indexOf(item)devolverá -1 si no se encuentra, esto podría resultar en la eliminación del elemento al final de la matriz si no lo verifica.
Ben Wilde
1
@ShibinRagh leer documentos para Array.prototype.splice ()
charlietfl
54

Esta es una respuesta correcta:

<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove=function($index){ 
  $scope.bdays.splice($index,1);     
}

En la respuesta de @ charlietfl. Creo que está mal, ya que pasas $indexcomo parámetro pero usas el deseo en su lugar en el controlador. Corrígeme si me equivoco :)

Dzung Nguyen
fuente
Parece que ambas respuestas son equivalentes, aunque su función puede aceptar el índice sin el $ y seguirá funcionando.
svarog
Esta debería ser la respuesta correcta. indexOfSOLO funciona si es IE9 +
levi
17
Esto no funcionará si tiene un pedido Por o un filtro en su ng-repeat
Joan-Diego Rodriguez
Esto funcionará mejor si ha utilizado track por $ index
Ankit Balyan
@ Joan-DiegoRodriguez ¿Cómo lo haría funcionar si tiene un filtro / pedido? No importa, solo lea la respuesta de
XMLilley
26

En caso de que estés dentro de una repetición

podría usar una opción de un solo revestimiento

    <div ng-repeat="key in keywords"> 
        <button ng-click="keywords.splice($index, 1)">

            {{key.name}}
        </button>
    </div>

$index es utilizado por angular para mostrar el índice actual de la matriz dentro ng-repeat

azerafati
fuente
1
Me gustó y usé este delineador
etoricky
24

El uso $indexfunciona perfectamente bien en casos básicos, y la respuesta de @ charlietfl es excelente. Pero a veces, $indexno es suficiente.

Imagine que tiene una sola matriz, que está presentando en dos ng-repeat's diferentes. Uno de esos ng-repeat es filtrado por objetos que tienen una propiedad de verdad, y el otro es filtrado por una propiedad de falsedad. Se presentan dos matrices filtradas diferentes, que se derivan de una matriz original única. (O, si ayuda a visualizar: tal vez tiene una sola matriz de personas, y desea una repetición de ng para las mujeres en esa matriz, y otra para los hombres en esa misma matriz ). Su objetivo: eliminar de manera confiable matriz original, utilizando información de los miembros de las matrices filtradas.

En cada una de esas matrices filtradas, $ index no será el índice del elemento dentro de la matriz original. Será el índice en la submatriz filtrada . Por lo tanto, no podrá distinguir el índice de la persona en la peoplematriz original , solo sabrá el $ index de la womeno mensub-matriz. Intenta eliminar usando eso, y tendrás elementos que desaparecerán de todas partes excepto donde quisieras. ¿Qué hacer?

Si tienes la suerte de estar usando un modelo de datos que incluye un identificador único para cada objeto, entonces úsalo en lugar de $ index para encontrar el objeto y splicesacarlo de la matriz principal. (Use mi ejemplo a continuación, pero con ese identificador único). ¿Pero si no tiene tanta suerte?

Angular en realidad aumenta cada elemento en una matriz ng repetida (en la matriz principal original) con una propiedad única llamada $$hashKey. Puede buscar una coincidencia en la matriz original $$hashKeydel elemento que desea eliminar y deshacerse de ella de esa manera.

Tenga en cuenta que $$hashKeyes un detalle de implementación, no incluido en la API publicada para ng-repeat. Podrían eliminar el soporte de esa propiedad en cualquier momento. Pero probablemente no. :-)

$scope.deleteFilteredItem = function(hashKey, sourceArray){
  angular.forEach(sourceArray, function(obj, index){
    // sourceArray is a reference to the original array passed to ng-repeat, 
    // rather than the filtered version. 
    // 1. compare the target object's hashKey to the current member of the iterable:
    if (obj.$$hashKey === hashKey) {
      // remove the matching item from the array
      sourceArray.splice(index, 1);
      // and exit the loop right away
      return;
    };
  });
}

Invocar con:

ng-click="deleteFilteredItem(item.$$hashKey, refToSourceArray)"

EDITAR: el uso de una función como esta, que utiliza teclas en $$hashKeylugar de un nombre de propiedad específico del modelo, también tiene la ventaja adicional significativa de hacer que esta función sea reutilizable en diferentes modelos y contextos. Proporcione su referencia de matriz y su referencia de elemento, y debería funcionar.

XML
fuente
10

Usualmente escribo en ese estilo:

<a class="btn" ng-click="remove($index)">Delete</a>


$scope.remove = function(index){
  $scope.[yourArray].splice(index, 1)
};

Espero que esto ayude. Debe usar un punto (.) Entre $ scope y [yourArray]

Sviatoslav Novosiadlyj
fuente
¿Cuál es el significado de "1" en (índice, 1)
ShibinRagh
@ShibinRagh Es el deleteCount. Un entero que indica el número de elementos de matriz antiguos que se deben eliminar. Si deleteCount es 0, no se eliminan elementos. En este caso, debe especificar al menos un nuevo elemento. Si deleteCount es mayor que el número de elementos que quedan en la matriz comenzando al inicio, entonces todos los elementos hasta el final de la matriz serán eliminados. Array.prototype.splice () Documentation
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
9

Sobre la base de la respuesta aceptada, esto va a trabajar con ngRepeat, filtery expectativas manejar mejor:

Controlador:

vm.remove = function(item, array) {
  var index = array.indexOf(item);
  if(index>=0)
    array.splice(index, 1);
}

Ver:

ng-click="vm.remove(item,$scope.bdays)"
Joan-Diego Rodriguez
fuente
No asignó, "eliminar" a $ scope.vm en su controlador, por lo que este código no funcionaría. Ahora, si hiciste esto ... $ scope.vm = {remove: function () {...}}, entonces lo haría.
Justin Russo
4

implementación sin un controlador.

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

<script>
  var app = angular.module("myShoppingList", []); 
</script>

<div ng-app="myShoppingList"  ng-init="products = ['Milk','Bread','Cheese']">
  <ul>
    <li ng-repeat="x in products track by $index">{{x}}
      <span ng-click="products.splice($index,1)">×</span>
    </li>
  </ul>
  <input ng-model="addItem">
  <button ng-click="products.push(addItem)">Add</button>
</div>

<p>Click the little x to remove an item from the shopping list.</p>

</body>
</html>

El método splice () agrega / elimina elementos a / de una matriz.

array.splice(index, howmanyitem(s), item_1, ....., item_n)

índice : obligatorio. Un número entero que especifica en qué posición agregar / eliminar elementos. Utilice valores negativos para especificar la posición desde el final de la matriz.

howmanyitem (s) : Opcional. El número de elementos que se eliminarán. Si se establece en 0, no se eliminarán elementos.

item_1, ..., item_n : Opcional. Los nuevos elementos que se agregarán a la matriz

Deepu Reghunath
fuente
1
Esta es la respuesta correcta. ¿Por qué confiar en un controlador para realizar llamadas simples de JavaScript?
Elle Fie
3

No estoy de acuerdo con que deba llamar a un método en su controlador. Debe usar un servicio para cualquier funcionalidad real, y debe definir directivas para cualquier funcionalidad para la escalabilidad y la modularidad, así como asignar un evento de clic que contenga una llamada al servicio que inyecte en su directiva.

Entonces, por ejemplo, en tu HTML ...

<a class="btn" ng-remove-birthday="$index">Delete</a>

Luego, crea una directiva ...

angular.module('myApp').directive('ngRemoveBirthday', ['myService', function(myService){
    return function(scope, element, attrs){
        angular.element(element.bind('click', function(){
            myService.removeBirthday(scope.$eval(attrs.ngRemoveBirthday), scope);  
        };       
    };
}])

Entonces a su servicio ...

angular.module('myApp').factory('myService', [function(){
    return {
        removeBirthday: function(birthdayIndex, scope){
            scope.bdays.splice(birthdayIndex);
            scope.$apply();
        }
    };
}]);

Cuando escriba su código correctamente de esta manera, hará que sea muy fácil escribir cambios futuros sin tener que reestructurar su código. Está organizado correctamente y maneja los eventos de clic personalizados correctamente mediante el enlace mediante directivas personalizadas.

Por ejemplo, si su cliente dice: "oye, ahora hagamos que llame al servidor y haga pan, y luego aparezca un modal". Podrá acceder fácilmente al servicio en sí mismo sin tener que agregar o cambiar ninguno de los códigos HTML o del método del controlador. Si solo tuviera una línea en el controlador, eventualmente necesitaría usar un servicio, para extender la funcionalidad al trabajo más pesado que solicita el cliente.

Además, si necesita otro botón 'Eliminar' en otro lugar, ahora tiene un atributo de directiva ('ng-remove-birthday') que puede asignar fácilmente a cualquier elemento de la página. Esto ahora lo hace modular y reutilizable. Esto será útil cuando se trate con el paradigma de componentes web PESADOS de Angular 2.0. No hay controlador en 2.0. :)

¡Feliz desarrollo!

Justin Russo
fuente
0

Si tiene ID o cualquier campo específico en su artículo, puede usar filter (). actúa como Where ().

<a class="btn" ng-click="remove(item)">Delete</a>

en el controlador:

$scope.remove = function(item) { 
  $scope.bdays = $scope.bdays.filter(function (element) {
                    return element.ID!=item.ID
                });
}
Seyed Reza Dadrezaei
fuente
0
Pass the id that you want to remove from the array to the given function 

desde el controlador (la función puede estar en el mismo controlador pero prefiere mantenerla en un servicio)

    function removeInfo(id) {
    let item = bdays.filter(function(item) {
      return bdays.id=== id;
    })[0];
    let index = bdays.indexOf(item);
    data.device.splice(indexOfTabDetails, 1);
  }
Utkarsh Joshi
fuente