Como remover um item de uma matriz no escopo AngularJS?

153

Lista de tarefas simples, mas com um botão excluir na página da lista para cada item:

insira a descrição da imagem aqui

HTML do modelo 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 relevante do controlador:

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

Eu tentei $scope.persons.pull(person)e $scope.persons.remove(person).

Embora o banco de dados tenha sido excluído com êxito, não consigo extrair este item do escopo e não quero fazer uma chamada de método para o servidor para obter dados que o cliente já possui, só quero remover essa pessoa do escopo.

Alguma ideia?

Tchau
fonte
Eu corro essa rota whit $, e a exibição não funciona bem. Eu sempre recebi uma página vazia depois de excluir :-(
zx1986 4/13
Ter escrito artigo semelhante codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh
não se trata tanto de excluir do escopo, mas de um array, e seria o mesmo, independentemente do angular, é apenas javascript
Xsmael

Respostas:

259

Seu problema não é realmente com Angular, mas com métodos Array. A maneira correta de remover um item específico de uma matriz é com Array.splice. Além disso, ao usar ng-repeat, você tem acesso ao especial$index propriedade , que é o índice atual da matriz pela qual você passou.

A solução é realmente bem direta:

Visão:

<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
fonte
1
@ScottMalachowski Você está certo. Eu esqueci essa parte. Revisei minha resposta para refletir isso, para que seja consistente com a sua.
Josh David Miller
13
Cuidado - essa solução baseada em índice não funcionará se você usar várias repetições ng do mesmo objeto em uma exibição (por exemplo, Tarefas agendadas, tarefas não agendadas, tarefas concluídas, todas saindo de $ scope.tasks) porque você terá vários itens com índice de 2, 3, 4, etc
shacker
O comentário acima, por @shacker, sobre várias repetições ng com diferentes conjuntos filtrados da mesma matriz, está correto. Use o método abaixo com o indexOf
Andrew Kuklewicz 29/04
4
@AndrewKuklewicz - indexOfpode ser uma operação mais cara; sem filtragem, é completamente desnecessário. Mas com a filtragem, indexOfseria o método apropriado.
Josh David Miller
Estou tendo problemas com isso e tive que fazer uma pequena alteração na geração de tags acima - estar - excluir ({{$ index}}) com o {{}}, caso contrário, obtive a string $ index - MAS tenho algo errado porque nunca chama esse método. Isso acontece quando eu removo qualquer menção ao índice, como delete (), mas isso realmente não ajuda.
Mikemil
310

Você precisará encontrar o índice do personem sua personsmatriz e, em seguida, usar o splicemétodo da matriz :

$scope.persons.splice( $scope.persons.indexOf(person), 1 );
Joseph Silber
fonte
49
esta é uma resposta melhor; funciona quando a lista foi filtrada para que esse índice na exibição não seja o mesmo que na matriz no escopo.
Andrew Kuklewicz
5
Esta é realmente a melhor resposta. Observe que, além dos casos de uso de listas filtradas mencionados por Andrew, essa abordagem também abrange o caso em que você exclui várias pessoas e as solicitações do Ajax para essas exclusões retornam fora de ordem. Se você usar os índices de linha antes do retorno da chamada do Ajax, você removerá as linhas incorretas.
Joris
4
É melhor em alguns casos, mas com indexOf você tem que iterar sobre todos os itens para encontrar o caminho certo, na resposta Josh você obter o índice e o item mais rápido
Daver
@mike - Use esse polyfill .
Joseph Silber
8

Eu usaria a biblioteca Underscore.js que possui uma lista de funções úteis.

without

without_.without(array, *values)

Retorna uma cópia da matriz com todas as instâncias dos valores removidos.

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

Exemplo

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

Veja Demo no JSFiddle .


filter

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

// => [2, 4, 6]

Exemplo

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

Veja a demonstração no Fiddle .

Maxim Shoustin
fonte
Eu provavelmente usaria $scope.nodes = _.without($scope.nodes, node);porque ele tem referência aonode
jake 13/06
Nos navegadores modernos, você pode usar Array.prototype.filter. _.filter(array, fun)torna-se array.filter(fun).
precisa saber é o seguinte
7
$scope.removeItem = function() {
    $scope.items.splice($scope.toRemove, 1);
    $scope.toRemove = null;
};

isso funciona para mim!

cebor
fonte
4

Se você tiver alguma função associada à lista, ao fazer a função de emenda, a associação também será excluída. Minha solução:

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

O parâmetro da lista é denominado itens . O parâmetro x.done indica se o item será excluído.

Outras referências: outro exemplo

Espero ajudá-lo. Saudações.

Drako
fonte
2

Para a resposta aceita de @ Joseph Silber não está funcionando, porque indexOf retorna -1. Provavelmente porque o Angular adiciona uma hashkey, que é diferente para o meu $ scope.items [0] e o meu item. Tentei resolver isso com a função angular.toJson (), mas não funcionou :(

Ah, eu descobri o motivo ... Eu uso um método chunk para criar duas colunas na minha tabela observando meus $ scope.items. Desculpe!

gabn88
fonte
2

Você também pode usar isso

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

Angular tem uma função interna chamada arrayRemove, no seu caso, o método pode ser simplesmente:

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

Para remover um elemento do escopo, use:

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

De indique descrição link aqui

Cubiczx
fonte