Angular Best Practices für den $Index von Ng-Repeat

Dieser Artikel erklärt die Best Practices von AngularJS und erklärt, warum Sie die Verwendung vermeiden sollten ng-repeat‘s $index. Es wurde ursprünglich auf meiner gepostet bloggen.


Ein Kunde hat gemeldet, dass er einen Artikel gelöscht hat, und der falsche Artikel wurde gelöscht!

Klingt nach einem ziemlich schweren Bug. Das haben wir einmal bei der Arbeit bekommen. Der Versuch, es zu lokalisieren, war ziemlich schwierig, da der Kunde natürlich keine Ahnung hatte, was er getan hatte, um das Problem zu reproduzieren.

Es stellte sich heraus, dass der Fehler durch die Verwendung verursacht wurde $index in einem (n ng-repeat. Lassen Sie uns einen Blick darauf werfen, wie das passiert, und einen supereinfachen Weg, um diese Art von Fehler vollständig zu vermeiden, und auch ein paar Lektionen, die wir daraus lernen können.

Eine einfache Liste mit einer Aktion

Schauen wir uns ein Beispiel für eine vollkommen gültige an ng-repeatund sein Controller.

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items">
    {{item.name}}
    <button ng-click="remove($index)">remove</button>
  </li>
</ul>
app.controller('ListCtrl', ['$scope', function($scope) {
  
  $scope.items = getItems();
 
  $scope.remove = function(index) {
    var item = $scope.items[index];
    removeItem(item);
  };
}]);

Sieht okay aus, oder? Nichts Besonderes an diesem Code.

Hinzufügen eines Filters

Nehmen wir jetzt eine kleine Änderung vor: Fügen wir der Liste einen Filter hinzu. Dies ist eine ziemlich übliche Vorgehensweise, wenn Sie eine lange Liste haben, um beispielsweise dem Benutzer zu ermöglichen, die Liste zu durchsuchen.

Nehmen Sie für dieses Beispiel an searchFilter ermöglicht es uns, die Liste nach einer Suchanfrage zu filtern.

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items | searchFilter">
    {{item.name}}
    <button ng-click="remove($index)">remove</button>
  </li>
</ul>

Der Controller-Code bleibt gleich. Sieht trotzdem gut aus, oder?

Da ist jetzt tatsächlich ein Bug drin. Kannst du es finden? Hätten Sie daran gedacht, wenn ich es nicht erwähnt hätte?

Verwenden $index sollte vermieden werden

Der Fehler liegt im Controller:

$scope.remove = function(index) {
  var item = $scope.items[index];
  removeItem(item);
};

Da wir hier den Index verwenden, werden wir auf Probleme stoßen, sobald wir die Liste so gefiltert haben, dass die Indizes nicht mit der ursprünglichen Liste übereinstimmen.

Glücklicherweise gibt es eine wirklich einfache Möglichkeit, dies zu vermeiden: Anstatt zu verwenden $indexlieber die eigentlichen Objekte herumreichen.

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items | searchFilter">
    {{item.name}}
    <button ng-click="remove(item)">remove</button>
  </li>
</ul>
$scope.remove = function(item) {
  removeItem(item);
};

Beachten Sie, wie ich mich verändert habe remove($index) hinein remove(item)und änderte die $scope.remove Funktion, um stattdessen direkt auf dem Objekt zu arbeiten.

Diese einfache Änderung vermeidet das Fehlerproblem vollständig.

Um das Problem und die Lösung besser zu veranschaulichen, können Sie dies verwenden interaktives Beispiel.

Was können wir daraus lernen?

Die erste Lektion ist natürlich, dass wir bei der Verwendung vorsichtig sein sollten $indexda es bei bestimmter Verwendung leicht Fehler verursachen kann.

Die zweite Lektion ist, dass Sie durch das Erkennen von Mustern wie diesem bessere Vorgehensweisen finden können, mit denen bestimmte Arten von Fehlern vollständig vermieden werden können. Ich empfehle definitiv jedem zu vermeiden $index jetzt, und als Ergebnis wird ihr Code weniger Fehler haben, nur durch diese einfache Änderung des Denkens.

Die dritte Lektion ist, dass Tests Ihnen nicht immer helfen werden. Selbst wenn Sie automatisierte Tests haben, die so etwas abdecken, ist es für sie ziemlich einfach, dies zu übersehen, da die dadurch verursachten Fehler so sehr von den spezifischen Eingaben abhängen. Der Fehler zeigt sich nicht immer, selbst wenn Filter verwendet werden.

Die vierte Lektion ist, die Abstraktion nicht zu durchbrechen – Diese ist sehr leicht zu übersehen. Technisch $index ist eine „Vorlagenvariable“, die von erstellt wurde ng-repeat. Es ist nur innerhalb des Wiederholungsblocks genau und hat eine Bedeutung. Wenn wir den Wert weitergeben, verliert er seinen Kontext und ist nicht mehr gültig. Damit es außerhalb der Wiederholung gültig ist, müssten wir die Liste auch in unserem Controller filtern, was eine Codeduplizierung erfordern würde, die vermieden werden sollte. Glücklicherweise kann das in diesem Artikel vorgestellte Muster verwendet werden, um dies zu vermeiden.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *