Wie lösche ich ein Element oder Objekt mit ng-click aus einem Array?

261

Ich versuche, eine Funktion zu schreiben, mit der ich ein Element entfernen kann, wenn auf die Schaltfläche geklickt wird, aber ich glaube, ich werde mit der Funktion verwechselt - verwende ich $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
quelle
2
Sie möchten $ Digest nicht, da dies zum Eingeben der Angular-Digest-Schleife verwendet wird (und Sie sich aufgrund des ng-Klicks bereits in einer Digest-Schleife befinden). Versuchen Sie, ein Element aus einem Array zu entfernen?
Mark Rajcok
@ MarkRajcok :) Ja, das ist, was ich versuche zu tun
Jess McKenzie
remove()in ng-clickder Art, wie Sie es haben, hat es keinen Kontext. Benötigen Sie weitere Details im Markup, um zu zeigen, was entfernt wird und ob es sich darin befindet ng-repeat, woher das zu entfernende Objekt stammt oder von welchem ​​Verhalten Sie möchtenremove()
charlietfl
@ charlietfl es ist innerhalb ng-repeat Ich habe die Frage aktualisiert
Jess McKenzie
Hier ist mein 1 Artikel, der erklärt, wie man einen Datensatz mit ng-repeat codepedia.info/angularjs-delete-table-row-tr-on-click löscht
Satinder singh

Antworten:

551

Um ein Element zu entfernen, müssen Sie es aus dem Array entfernen und können das bdayElement im Markup an Ihre Entfernungsfunktion übergeben. Suchen Sie dann im Controller den Index des Elements und entfernen Sie ihn aus dem Array

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

Dann in der Steuerung:

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

Angular erkennt automatisch die Änderung am bdaysArray und führt die Aktualisierung von durchng-repeat

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

BEARBEITEN: Wenn Live-Updates mit dem Server einen von Ihnen erstellten Dienst verwenden $resource, um die Array-Updates zu verwalten, während der Server aktualisiert wird

charlietfl
quelle
62
Die $indexdirekte Verwendung kann Fehler erzeugen, wenn Ihre Liste nach Vorlage gefiltert wird. Es ist eine Vorlagensache; es ist sicherer in der Anwendung ng-click='remove(bday)'dannarr.splice(arr.indexOf(bday),1);
Umur Kontacı
6
Sie müssen $ index nicht übergeben, da Sie 'this' innerhalb der Methode verwenden können. $ scope.remove = function () {$ scope.bdays.splice (this. $ index, 1); }
Matchdav
1
@ Matthewdavidson this is undefined. Plunker / jsfiddle vielleicht?
Tjorriemorrie
11
.indexOf(item)Gibt -1 zurück, wenn es nicht gefunden wird. Dies kann dazu führen, dass das Element am Ende des Arrays entfernt wird, wenn Sie nicht danach suchen.
Ben Wilde
1
@ShibinRagh las Dokumente für Array.prototype.splice ()
charlietfl
54

Dies ist eine richtige Antwort:

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

In der Antwort von @ charlietfl. Ich denke, es ist falsch, da Sie $indexals Parameter übergeben, aber Sie verwenden den Wunsch stattdessen in Controller. Korrigiere mich, wenn ich falsch liege :)

Dzung Nguyen
quelle
Es sieht so aus, als wären beide Antworten gleichwertig, obwohl Ihre Funktion einen Index ohne das $ akzeptieren kann und es trotzdem funktioniert.
Svarog
Dies sollte die richtige Antwort sein. indexOfFunktioniert NUR, wenn es IE9 + ist
Levi
17
Dies wird nicht funktionieren, wenn Sie eine Bestellung oder einen Filter in Ihrer ng-Wiederholung haben
Joan-Diego Rodriguez
Dies wird besser funktionieren, wenn Sie Track von $ Index verwendet haben
Ankit Balyan
@ Joan-DiegoRodriguez Wie würden Sie es zum Laufen bringen, wenn Sie einen Filter / eine Bestellung haben? Egal, lesen Sie einfach XMLilleys Antwort
Jamesmstone
26

Für den Fall, dass Sie sich in einer ng-Wiederholung befinden

Sie könnten eine Einzeiler-Option verwenden

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

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

$index wird von Angular verwendet, um den aktuellen Index des Arrays im Inneren anzuzeigen ng-repeat

Azerafati
quelle
1
Ich mag und benutzte diesen einen Liner
etoricky
24

Die Verwendung $indexfunktioniert in einfachen Fällen einwandfrei, und die Antwort von @ charlietfl ist großartig. Aber manchmal,$index ist das nicht genug.

Stellen Sie sich vor, Sie haben ein einzelnes Array, das Sie in zwei verschiedenen ng-Wiederholungen präsentieren. Eine dieser ng-Wiederholungen wird nach Objekten gefiltert, die eine wahrheitsgemäße Eigenschaft haben, und die andere wird nach einer fälschlichen Eigenschaft gefiltert. Es werden zwei verschiedene gefilterte Arrays vorgestellt, die von einem einzelnen Original-Array abgeleitet sind. (Oder, wenn es zur Visualisierung beiträgt: Vielleicht haben Sie eine einzelne Gruppe von Personen, und Sie möchten eine ng-Wiederholung für die Frauen in dieser Gruppe und eine andere für die Männer in derselben Gruppe .) Ihr Ziel: Löschen Sie zuverlässig aus dem Original-Array unter Verwendung von Informationen aus den Mitgliedern der gefilterten Arrays.

In jedem dieser gefilterten Arrays ist $ index nicht der Index des Elements im ursprünglichen Array. Dies ist der Index im gefilterten Unterarray . Sie können also den Index der Person im ursprünglichen peopleArray nicht erkennen, sondern kennen den $ index nur aus dem womenoder dem menUnterarray. Versuchen Sie, damit zu löschen, und Sie werden Elemente von überall verschwinden lassen, außer wo Sie wollten. Was ist zu tun?

Wenn Sie das Glück haben, dass ein Datenmodell eine eindeutige Kennung für jedes Objekt enthält, verwenden Sie diese anstelle von $ index, um das Objekt und splicees aus dem Hauptarray zu finden. (Verwenden Sie mein Beispiel unten, aber mit dieser eindeutigen Kennung.) Aber wenn Sie nicht so viel Glück haben?

Angular erweitert tatsächlich jedes Element in einem ng-wiederholten Array (im Hauptarray) mit einer eindeutigen Eigenschaft namens $$hashKey. Sie können das ursprüngliche Array nach einer Übereinstimmung $$hashKeymit dem Element durchsuchen, das Sie löschen möchten, und es auf diese Weise entfernen.

Beachten Sie, dass dies $$hashKeyein Implementierungsdetail ist, das nicht in der veröffentlichten API für ng-repeat enthalten ist. Sie können die Unterstützung für diese Eigenschaft jederzeit entfernen. Aber wahrscheinlich nicht. :-)

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

Rufen Sie auf mit:

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

BEARBEITEN: Die Verwendung einer solchen Funktion, bei der $$hashKeyanstelle eines modellspezifischen Eigenschaftsnamens ein Schlüssel verwendet wird , hat auch den wesentlichen zusätzlichen Vorteil, dass diese Funktion für verschiedene Modelle und Kontexte wiederverwendbar ist. Geben Sie Ihre Array-Referenz und Ihre Artikelreferenz an, und es sollte einfach funktionieren.

XML
quelle
10

Normalerweise schreibe ich so:

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


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

Ich hoffe, dies hilft Ihnen. Sie müssen einen Punkt (.) Zwischen $ scope und [yourArray] verwenden.

Sviatoslav Novosiadlyj
quelle
Was bedeutet "1" in (Index, 1)
ShibinRagh
@ShibinRagh Es ist das deleteCount. Eine Ganzzahl, die die Anzahl der zu entfernenden alten Array-Elemente angibt. Wenn deleteCount 0 ist, werden keine Elemente entfernt. In diesem Fall sollten Sie mindestens ein neues Element angeben. Wenn deleteCount größer ist als die Anzahl der Elemente, die ab dem Start im Array verbleiben, werden alle Elemente bis zum Ende des Arrays gelöscht. Array.prototype.splice () Dokumentation
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
9

Aufbauend auf der akzeptierten Antwort funktioniert dies mit ngRepeat:filter und der Griff expections besser:

Regler:

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

Aussicht:

ng-click="vm.remove(item,$scope.bdays)"
Joan-Diego Rodriguez
quelle
Sie haben $ scope.vm in Ihrem Controller nicht "remove" zugewiesen, sodass dieser Code nicht funktioniert. Wenn Sie dies nun tun würden ... $ scope.vm = {remove: function () {...}}, dann wäre es so.
Justin Russo
4

Implementierung ohne Controller.

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

Die splice () -Methode fügt einem Array Elemente hinzu oder entfernt sie.

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

Index : Erforderlich. Eine Ganzzahl, die angibt, an welcher Position Elemente hinzugefügt / entfernt werden sollen. Verwenden Sie negative Werte, um die Position am Ende des Arrays anzugeben.

howmanyitem (s) : Optional. Die Anzahl der zu entfernenden Elemente. Bei der Einstellung 0 werden keine Elemente entfernt.

item_1, ..., item_n : Optional. Die neuen Elemente, die dem Array hinzugefügt werden sollen

Deepu Reghunath
quelle
1
Das ist die richtige Antwort. Warum sollten Sie sich auf einen Controller verlassen, um einfache JavaScript-Aufrufe auszuführen?
Elle Fie
3

Ich bin nicht der Meinung, dass Sie eine Methode auf Ihrem Controller aufrufen sollten. Sie sollten einen Dienst für jede tatsächliche Funktionalität verwenden und Anweisungen für jede Funktionalität für Skalierbarkeit und Modularität definieren sowie ein Klickereignis zuweisen, das einen Aufruf des Dienstes enthält, den Sie in Ihre Anweisung einfügen.

Also zum Beispiel auf Ihrem HTML ...

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

Dann erstellen Sie eine Direktive ...

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

Dann in Ihrem Dienst ...

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

Wenn Sie Ihren Code so richtig schreiben, können Sie künftige Änderungen ganz einfach schreiben, ohne Ihren Code neu strukturieren zu müssen. Es ist ordnungsgemäß organisiert und Sie behandeln benutzerdefinierte Klickereignisse korrekt, indem Sie mithilfe benutzerdefinierter Anweisungen binden.

Wenn Ihr Client beispielsweise sagt: "Hey, jetzt rufen wir den Server an, machen Brot und öffnen dann ein Modal." Sie können ganz einfach zum Dienst selbst wechseln, ohne HTML- und / oder Controller-Methodencode hinzufügen oder ändern zu müssen. Wenn Sie nur eine Zeile auf dem Controller hätten, müssten Sie möglicherweise einen Dienst verwenden, um die Funktionalität auf das vom Client gewünschte schwerere Heben auszudehnen.

Wenn Sie an anderer Stelle eine andere Schaltfläche zum Löschen benötigen, verfügen Sie jetzt über ein Direktivenattribut ('ng-remove-geburtstag'), das Sie jedem Element auf der Seite problemlos zuweisen können. Dies macht es jetzt modular und wiederverwendbar. Dies ist nützlich, wenn Sie sich mit dem Paradigma der HEAVY-Webkomponenten von Angular 2.0 befassen. In 2.0 gibt es keinen Controller. :) :)

Viel Spaß beim Entwickeln !!!

Justin Russo
quelle
0

Wenn Sie eine ID oder ein bestimmtes Feld in Ihrem Artikel haben, können Sie filter () verwenden. seine Handlung wie Where ().

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

im Controller:

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

von der Steuerung (Funktion kann sich in derselben Steuerung befinden, es jedoch vorziehen, sie in einem Dienst zu behalten)

    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
quelle