Como faço para excluir um item ou objeto de uma matriz usando o ng-click?

261

Estou tentando escrever uma função que permita remover um item quando o botão é clicado, mas acho que estou ficando confuso com a função - eu uso $digest?

HTML & 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
fonte
2
Você não deseja $ digest, pois é usado para inserir o loop digest do Angular (e você já está em um loop digest por causa do ng-click). Você está tentando remover um item de uma matriz?
Mark Rajcok
Isso é @MarkRajcok :) sim que estou tentando fazer
Jess McKenzie
remove()ng-clickna maneira que você tem não tem contexto. Precisa de mais detalhes na marcação para mostrar o que está sendo removido e se está dentro ng-repeatou onde o item a ser removido vem, ou o comportamento que você quer deremove()
charlietfl
@charlietfl é dentro ng-repeat Eu atualizei a questão
Jess McKenzie
Heres meu 1 artigo que explica como excluir registro com ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh

Respostas:

552

Para remover o item, você precisa removê-lo da matriz e pode passar o bdayitem para sua função de remoção na marcação. Em seguida, no controlador, procure o índice do item e remova-o da matriz

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

Então no controlador:

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

O Angular detectará automaticamente a alteração na bdaysmatriz e fará a atualização dong-repeat

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

EDIT: se fazer atualizações ao vivo com o servidor usaria um serviço criado por você $resourcepara gerenciar as atualizações da matriz ao mesmo tempo em que atualiza o servidor

charlietfl
fonte
62
Usar $indexdiretamente pode gerar bugs se sua lista estiver filtrada no modelo. É uma coisa de modelo; é mais seguro usá-lo ng-click='remove(bday)'entãoarr.splice(arr.indexOf(bday),1);
Umur Kontacı
6
Você não precisa passar o $ index porque pode usar 'this' dentro do método. $ scope.remove = function () {$ scope.bdays.splice (este. $ index, 1); }
matchdav 10/08/13
1
@matthewdavidson this is undefined. Plunker / jsfiddle talvez?
Tjorriemorrie 19/09/2013
11
.indexOf(item)retornará -1 se não for encontrado, isso poderá resultar na remoção do item no final da matriz, se você não o verificar.
Ben Wilde
1
@ShibinRagh leu os documentos para Array.prototype.splice ()
charlietfl
54

Esta é uma resposta correta:

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

Na resposta de @ charlietfl. Eu acho que está errado, já que você passa $indexcomo parâmetro, mas usa o desejo no controlador. Corrija-me se eu estiver errado :)

Dzung Nguyen
fonte
parece que as duas respostas são equivalentes, embora sua função possa aceitar o índice sem o $ e ainda funcione.
Svarog
essa deve ser a resposta correta. indexOfFunciona apenas se for IE9 + #
levi 24/02
17
Isso não vai funcionar se você tem um orderBy ou um filtro em sua ng-repeat
Joan-Diego Rodriguez
Isso vai funcionar melhor, se você tiver usado trilha por $ index
Ankit Balyan
@ Joan-DiegoRodriguez Como você fazê-lo funcionar se você tem um filtro / orderby Não importa apenas ler de XMLilley Resposta
jamesmstone
26

Caso você esteja dentro de um ng-repeat

você pode usar uma opção de um forro

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

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

$index é usado por angular para mostrar o índice atual da matriz dentro ng-repeat

azerafati
fonte
1
Eu gosto e usei este forro
etoricky 04/12/19
24

O uso $indexfunciona perfeitamente bem em casos básicos, e a resposta do @ charlietfl é ótima. Mas, às vezes, $indexnão é suficiente.

Imagine que você tem uma única matriz, que você está apresentando em duas repetições ng diferentes. Um desses ng-repeat's é filtrado para objetos que possuem uma propriedade de verdade e o outro é filtrado para uma propriedade false. Duas matrizes filtradas diferentes estão sendo apresentadas, que derivam de uma única matriz original. (Ou, se ajudar a visualizar: talvez você tenha uma única matriz de pessoas e deseje uma repetição de ng para as mulheres dessa matriz e outra para os homens dessa mesma matriz .) Seu objetivo: excluir com segurança o matriz original, usando informações dos membros das matrizes filtradas.

Em cada uma dessas matrizes filtradas, $ index não será o índice do item na matriz original. Será o índice no sub-array filtrado . Portanto, você não será capaz de informar o índice da pessoa na peoplematriz original , apenas conhecerá o índice $ da womenou mensub-matriz. Tente excluir usando isso, e você terá itens desaparecendo de todos os lugares, exceto onde você queria. O que fazer?

Se você tiver a sorte de usar um modelo de dados, inclua um identificador exclusivo para cada objeto, use-o em vez de $ index, para encontrar o objeto e spliceele fora da matriz principal. (Use meu exemplo abaixo, mas com esse identificador exclusivo.) Mas se você não tiver tanta sorte?

Angular na verdade aumenta cada item em uma matriz ng-repetida (na matriz original principal) com uma propriedade exclusiva chamada $$hashKey. Você pode pesquisar na matriz original por uma correspondência $$hashKeydo item que deseja excluir e se livrar dessa maneira.

Observe que este $$hashKeyé um detalhe de implementação, não incluído na API publicada para ng-repeat. Eles podem remover o suporte para essa propriedade a qualquer momento. Mas provavelmente não. :-)

$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 com:

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

EDIT: O uso de uma função como essa, que digita o $$hashKeynome da propriedade em vez de um nome de propriedade específico do modelo, também tem a vantagem adicional de tornar essa função reutilizável em diferentes modelos e contextos. Forneça sua referência de matriz e referência de item, e deve funcionar.

XML
fonte
10

Eu costumo escrever com esse estilo:

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


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

Espero que isso ajude Você precisa usar um ponto (.) Entre $ scope e [yourArray]

Sviatoslav Novosiadlyj
fonte
Qual é o significado de "1" em (index, 1)
ShibinRagh 15/09/15
@ShibinRagh É o deleteCount. Um número inteiro indicando o número de elementos antigos da matriz a serem removidos. Se deleteCount for 0, nenhum elemento será removido. Nesse caso, você deve especificar pelo menos um novo elemento. Se deleteCount for maior que o número de elementos restantes na matriz, iniciando no início, todos os elementos até o final da matriz serão excluídos. Array.prototype.splice () Documentação
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
9

Com base na resposta aceita, isso vai trabalhar com ngRepeat, filtere expections lidar melhor:

Controlador:

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

Visão:

ng-click="vm.remove(item,$scope.bdays)"
Rodriguez, Joan-Diego
fonte
Você não atribuiu "remove" a $ scope.vm no seu controlador, portanto esse código não funcionaria. Agora, se você fez isso ... $ scope.vm = {remove: function () {...}}, o faria.
Justin Russo
4

implementação sem um 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>

O método splice () adiciona / remove itens de / para uma matriz.

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

índice : obrigatório. Um número inteiro que especifica em que posição adicionar / remover itens. Use valores negativos para especificar a posição no final da matriz.

howmanyitem : Opcional. O número de itens a serem removidos. Se definido como 0, nenhum item será removido.

item_1, ..., item_n : opcional. Os novos itens a serem adicionados à matriz

Deepu Reghunath
fonte
1
Esta é a resposta certa. Por que confiar em um controlador para executar chamadas JavaScript simples?
Elle Fie
3

Discordo que você deveria estar chamando um método no seu controlador. Você deve usar um serviço para qualquer funcionalidade real e definir diretivas para qualquer funcionalidade para escalabilidade e modularidade, além de atribuir um evento de clique que contenha uma chamada para o serviço que você injeta em sua diretiva.

Então, por exemplo, no seu HTML ...

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

Em seguida, crie uma diretiva ...

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

Então em seu serviço ...

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

Quando você escreve seu código corretamente dessa maneira, facilita a gravação de alterações futuras sem precisar reestruturá-lo. Ele está organizado corretamente e você está manipulando eventos de clique personalizados corretamente vinculando usando diretivas personalizadas.

Por exemplo, se o seu cliente disser: "ei, agora vamos chamar o servidor e fazer pão e, em seguida, exibir um modal". Você poderá acessar facilmente o próprio serviço sem precisar adicionar ou alterar nenhum código de método HTML e / ou controlador. Se você tivesse apenas uma linha no controlador, acabaria precisando usar um serviço, para estender a funcionalidade ao levantamento mais pesado que o cliente está solicitando.

Além disso, se você precisar de outro botão 'Excluir' em outro lugar, agora terá um atributo de diretiva ('ng-remove-birthday') que poderá atribuir facilmente a qualquer elemento da página. Isso agora o torna modular e reutilizável. Isso será útil ao lidar com o paradigma HEAVY de componentes da web do Angular 2.0. Não há controlador no 2.0. :)

Desenvolvimento feliz !!!

Justin Russo
fonte
0

se você tiver um ID ou algum campo específico em seu item, poderá usar filter (). age como Where ().

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

no controlador:

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

do controlador (a função pode estar no mesmo controlador, mas prefere mantê-lo em serviço)

    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
fonte