Jak usunąć element lub obiekt z tablicy za pomocą kliknięcia ng?

261

Próbuję napisać funkcję, która pozwala mi usunąć element po kliknięciu przycisku, ale myślę, że mylę się z funkcją - czy używam $digest?

HTML i 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
źródło
2
Nie chcesz $ digest, ponieważ służy on do wejścia w pętlę skrótu Angulara (i już jesteś w pętli skrótu z powodu kliknięcia ng). Czy próbujesz usunąć element z tablicy?
Mark Rajcok
@MarkRajcok :) tak to właśnie próbuję zrobić
Jess McKenzie
remove()w ng-clickdrodze masz to ma kontekst. Potrzebujesz więcej szczegółów w znacznikach, aby pokazać, co jest usuwane i czy jest w ng-repeatremove()
środku
@charlietfl jest w ciągu ng-repeat Zaktualizowałem pytanie
Jess McKenzie
Oto mój 1 artykuł, który wyjaśnia, jak usunąć rekord za pomocą ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click
Satinder singh

Odpowiedzi:

551

Aby usunąć element, musisz usunąć go z tablicy i przekazać bdayelement do funkcji usuwania w znacznikach. Następnie w kontrolerze sprawdź indeks elementu i usuń go z tablicy

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

Następnie w kontrolerze:

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

Angular automatycznie wykryje zmianę w bdaystablicy i dokona aktualizacjing-repeat

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

EDYCJA: Jeśli przeprowadzanie aktualizacji na żywo za pomocą serwera będzie korzystało z usługi utworzonej za pomocą $resourcedo zarządzania aktualizacjami macierzy w tym samym czasie, gdy aktualizuje serwer

Charlietfl
źródło
62
Korzystanie $indexbezpośrednio może generować błędy, jeśli twoja lista jest filtrowana według szablonu. To jest szablon; bezpieczniej jest ng-click='remove(bday)'wtedy używaćarr.splice(arr.indexOf(bday),1);
Umur Kontacı
6
Nie musisz przekazywać $ index, ponieważ możesz użyć „this” w metodzie. $ scope.remove = function () {$ scope.bdays.splice (this. $ index, 1); }
matchdav,
1
@matthewdavidson this is undefined. Może Plunker / jsfiddle?
Tjorriemorrie,
11
.indexOf(item)zwróci -1, jeśli nie zostanie znaleziony, może to spowodować usunięcie elementu na końcu tablicy, jeśli go nie zaznaczysz.
Ben Wilde
1
@ShibinRagh czytał dokumenty dla Array.prototype.splice ()
charlietfl
54

To poprawna odpowiedź:

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

W odpowiedzi @ charlietfl. Myślę, że to źle, ponieważ podajesz $indexjako parametr, ale zamiast tego używasz życzenia w kontrolerze. Popraw mnie, jeśli się mylę :)

Dzung Nguyen
źródło
wygląda na to, że obie odpowiedzi są równoważne, chociaż twoja funkcja może zaakceptować indeks bez $ i nadal będzie działać.
svarog
to powinna być poprawna odpowiedź. indexOfDziała TYLKO, jeśli jest to IE9 +
levi
17
To nie zadziała, jeśli masz zamówienie lub filtr w powtórzeniu ng
Joan-Diego Rodriguez
Będzie to działać lepiej, jeśli
używałeś
@ Joan-DiegoRodriguez Jak sprawiłbyś, żeby działało, jeśli masz filtr / zamówienie Nieważne, po prostu przeczytaj odpowiedź
XMLilleya
26

Jeśli jesteś w powtórzeniu ng

możesz użyć opcji jednej linijki

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

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

$index jest używany przez angular, aby pokazać aktualny indeks tablicy wewnątrz ng-repeat

azerafati
źródło
1
Podobał mi się ten jeden liniowiec
etoricky
24

Używanie $indexdziała doskonale w podstawowych przypadkach, a odpowiedź @ charlietfl jest świetna. Ale czasami $indexto nie wystarczy.

Wyobraź sobie, że masz jedną tablicę, którą prezentujesz w dwóch różnych powtórzeniach ng. Jeden z powtórzeń ng jest filtrowany pod kątem obiektów, które mają prawdziwą właściwość, a drugi jest filtrowany pod kątem właściwości fałsz. Prezentowane są dwie różne tablice filtrowane, które pochodzą z pojedynczej oryginalnej tablicy. (Lub, jeśli to pomaga w wizualizacji: być może masz jedną grupę ludzi i chcesz jedno powtórzenie ng dla kobiet w tej tablicy, a drugie dla mężczyzn w tej samej tablicy .) Twój cel: niezawodne usunięcie z oryginalna tablica, wykorzystująca informacje od członków filtrowanych tablic.

W każdej z tych filtrowanych tablic $ index nie będzie indeksem elementu w oryginalnej tablicy. Będzie to indeks w filtrowanej pod-macierzy . Tak więc, nie będzie w stanie powiedzieć, indeks osoby w oryginalnej peopletablicy, będziesz wiedzieć tylko indeks $ z womenlub mensub-macierzy. Spróbuj usunąć za pomocą tego, a będziesz znikał z każdego miejsca, z wyjątkiem miejsca, w którym chciałeś. Co robić?

Jeśli masz szczęście, że używasz modelu danych zawierającego unikalny identyfikator dla każdego obiektu, użyj go zamiast $ index, aby znaleźć obiekt i splicego z głównej tablicy. (Użyj mojego przykładu poniżej, ale z tym unikalnym identyfikatorem.) Ale jeśli nie masz tyle szczęścia?

Angular w rzeczywistości zwiększa każdy element w tablicy z powtórzeniami ng (w głównej, oryginalnej tablicy) o unikalną właściwość o nazwie $$hashKey. Możesz przeszukać oryginalną tablicę pod kątem dopasowania $$hashKeyelementu, który chcesz usunąć, i w ten sposób się go pozbyć.

Należy pamiętać, że $$hashKeyjest to szczegół implementacji, nieuwzględniony w opublikowanym interfejsie API dla ng-repeat. Mogą w dowolnym momencie usunąć obsługę tej właściwości. Ale prawdopodobnie nie. :-)

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

Wywołaj z:

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

EDYCJA: Użycie takiej funkcji, która wprowadza $$hashKeyzamiast nazwy właściwości specyficznej dla modelu, ma również znaczącą dodatkową zaletę polegającą na tym, że można użyć tej funkcji w różnych modelach i kontekstach. Podaj je z odniesieniem do tablicy i odniesieniem do przedmiotu, a powinno po prostu działać.

XML
źródło
10

Zwykle piszę w takim stylu:

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


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

Mam nadzieję, że to pomoże Ci użyć kropki (.) Pomiędzy $ scope a [yourArray]

Sviatoslav Novosiadlyj
źródło
Co oznacza „1” w (indeks, 1)
ShibinRagh
@ShibinRagh It's the deleteCount. Liczba całkowita wskazująca liczbę starych elementów tablicy do usunięcia. Jeśli deleteCount ma wartość 0, żadne elementy nie są usuwane. W takim przypadku należy podać co najmniej jeden nowy element. Jeśli deleteCount jest większa niż liczba elementów pozostałych w tablicy, zaczynając od początku, wówczas wszystkie elementy do końca tablicy zostaną usunięte. Dokumentacja Array.prototype.splice ()
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
9

Opierając się na przyjętej odpowiedź, to będzie pracować ngRepeat, filtera moje oczekiwania uchwyt lepiej:

Kontroler:

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

Widok:

ng-click="vm.remove(item,$scope.bdays)"
Joan-Diego Rodriguez
źródło
Nie przypisałeś „usuń” do $ scope.vm w kontrolerze, więc ten kod nie będzie działać. Teraz, jeśli zrobiłeś to ... $ scope.vm = {remove: function () {...}}, to by to zrobił.
Justin Russo,
4

wdrożenie bez kontrolera.

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

Metoda splice () dodaje / usuwa elementy do / z tablicy.

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

indeks : wymagane. Liczba całkowita określająca, w której pozycji dodawać / usuwać elementy. Użyj wartości ujemnych, aby określić pozycję od końca tablicy.

howmanyitem (s) : Opcjonalne. Liczba elementów do usunięcia. Jeśli ustawione na 0, żadne elementy nie zostaną usunięte.

item_1, ..., item_n : opcjonalnie. Nowe elementy do dodania do tablicy

Deepu Reghunath
źródło
1
To jest właściwa odpowiedź. Po co polegać na kontrolerze wykonującym proste wywołania JavaScript?
Elle Fie
3

Nie zgadzam się, że powinieneś wywoływać metodę na kontrolerze. Powinieneś korzystać z usługi dla dowolnej faktycznej funkcjonalności i powinieneś definiować dyrektywy dla dowolnej funkcjonalności skalowalności i modułowości, a także przypisywać zdarzenie kliknięcia, które zawiera wywołanie usługi, którą wstrzykujesz do swojej dyrektywy.

Na przykład na HTML ...

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

Następnie utwórz dyrektywę ...

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

Następnie do usług ...

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

Kiedy napiszesz poprawnie swój kod, bardzo ułatwisz pisanie przyszłych zmian bez konieczności jego restrukturyzacji. Jest on odpowiednio zorganizowany, a zdarzenia niestandardowe kliknięcia są obsługiwane poprawnie przez wiązanie przy użyciu niestandardowych dyrektyw.

Na przykład, jeśli twój klient mówi: „hej, zróbmy teraz połączenie z serwerem i przygotuj chleb, a następnie wyskakuj modal”. Będziesz mógł łatwo przejść do samej usługi bez konieczności dodawania lub zmiany kodu HTML i / lub kodu metody kontrolera. Jeśli masz tylko jedną linię na kontrolerze, w końcu będziesz musiał skorzystać z usługi, aby rozszerzyć funkcjonalność do cięższego podnoszenia, o który prosi klient.

Ponadto, jeśli potrzebujesz innego przycisku „Usuń” w innym miejscu, masz teraz atrybut dyrektywy („ng-remove-birthday”), który możesz łatwo przypisać do dowolnego elementu na stronie. Dzięki temu jest teraz modułowy i wielokrotnego użytku. Przyda się to w przypadku paradygmatu komponentów sieciowych HEAVY w Angular 2.0. W 2.0 nie ma kontrolera. :)

Happy Developing !!!

Justin Russo
źródło
0

jeśli masz identyfikator lub dowolne określone pole w swoim elemencie, możesz użyć filter (). zachowuje się jak Where ().

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

w kontrolerze:

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

z kontrolera (funkcja może znajdować się w tym samym kontrolerze, ale wolisz zachować ją w usłudze)

    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
źródło