Zrozumienie wyrażenia ngRepeat „track by”

102

Mam trudności ze zrozumieniem, jak działa utwór wyrażony przez wyrażenie ng-repeat w angularjs. Dokumentacja jest bardzo rzadka: http://docs.angularjs.org/api/ng/directive/ngRepeat

Czy możesz wyjaśnić, jaka jest różnica między tymi dwoma fragmentami kodu pod względem wiązania danych i innych istotnych aspektów?

z: track by $index

<!--names is an array-->
<div ng-repeat="(key, value) in names track by $index">
  <input ng-model="value[key]">                         
</div>

bez (to samo wyjście)

<!--names is an array-->
<div ng-repeat="(key, value) in names">
   <input ng-model="value[key]">                         
</div>
Jonathan Grupp
źródło
Świetne pytanie z bardzo dobrymi odpowiedziami! Szkoda, że ​​PO nie przyjął odpowiedzi - lub nie sądzisz, że odpowiedź na pytanie jest prawidłowa?
Mawg mówi, że przywróć Monikę
Masz rację! Właśnie zaakceptowałem odpowiedź TJ'a.
Jonathan Grupp,

Odpowiedzi:

97

Możesz, track by $indexjeśli źródło danych ma zduplikowane identyfikatory

na przykład: $scope.dataSource: [{id:1,name:'one'}, {id:1,name:'one too'}, {id:2,name:'two'}]

Nie możesz iterować tej kolekcji, używając „id” jako identyfikatora (zduplikowany identyfikator: 1).

NIE DZIAŁA:

<element ng-repeat="item.id as item.name for item in dataSource">
  // something with item ...
</element>

ale możesz, jeśli używasz track by $index:

<element ng-repeat="item in dataSource track by $index">
  // something with item ...
</element>
nilsK
źródło
1
Dziękuję za odpowiedź! Ale z pewnością zduplikowane identyfikatory nie są jedynym przypadkiem użycia. Chciałbym też wiedzieć, co się dzieje „pod maską”.
Jonathan Grupp
2
cóż, to proste: wystarczy spojrzeć na kod , wszystko to jest open source;)
nilsK
4
To pytanie jest stare, ale nadal myślę, że może pomóc lepiej zrozumieć bennadel.com/blog/ ... krótką wersję wyjaśnienia tutaj docs.angularjs.org/error/ngRepeat/dupes
Annapoorni D
3
Jeszcze jedna rzecz, którą należy wziąć pod uwagę, to fakt, że jeśli możesz używać funkcji śledzenia według klucza, uzyskasz lepszą wydajność (blog.500tech.com/is-reactjs-fast). Ta funkcja umożliwia powiązanie obiektu JavaScript z węzłem ngRepeat DOM (Document Object Model) przy użyciu unikalnego identyfikatora. Dzięki temu powiązaniu AngularJS nie będzie niepotrzebnie niszczyć i ponownie tworzyć węzłów DOM. Może to przynieść ogromne korzyści w zakresie wydajności i wygody użytkownika ( bennadel.com/blog/… ).
Braulio
Mam listę 700 dziwnych pozycji. Czas renderowania wzrósł z 4 sekund do 100 ms. Track by powinien być używany dla wszystkich ngRepeat na podstawie danych pochodzących z reszty.
Patrick
60

krótkie podsumowanie:

track by jest używany w celu powiązania danych z generacją DOM (i głównie ich ponownym generowaniem) wykonaną przez ng-repeat.

kiedy dodajesz track by, w zasadzie mówisz angularowi, żeby wygenerował pojedynczy element DOM na obiekt danych w danej kolekcji

może to być przydatne podczas stronicowania i filtrowania lub w każdym przypadku, gdy obiekty są dodawane lub usuwane z ng-repeatlisty.

zazwyczaj bez track byangular łączy obiekty DOM z kolekcją, wstrzykując właściwość expando - $$hashKey- do twoich obiektów JavaScript i ponownie ją generuje (i ponownie kojarzy obiekt DOM) przy każdej zmianie.

pełne wyjaśnienie:

http://www.bennadel.com/blog/2556-using-track-by-with-ngrepeat-in-angularjs-1-2.htm

bardziej praktyczny przewodnik:

http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/

(śledzenie jest dostępne pod kątem> 1,2)

Nuriel
źródło
8

Jeśli pracujesz z obiektami śledzonymi według identyfikatora (np. $ Index) zamiast z całym obiektem i ponownie załadujesz dane później, ngRepeat nie odbuduje elementów DOM dla elementów, które już wyrenderował , nawet jeśli obiekty JavaScript w kolekcji mają zostały zastąpione nowymi.

ram1993
źródło
jakieś odniesienie, które to potwierdza?
azerafati
czy istnieje sposób na wymuszenie ponownego renderowania? czy jakieś inne obejście? nigdzie nie znalazłem tego wspomnianego, ale uważam, że to właśnie tworzy dla mnie bałagan i już zmarnowałem dużo czasu.
NeverGiveUp161
1
albo nie używaj funkcji śledzenia, ani nie zmieniaj unikalnego identyfikatora przy zmianie obiektu. Zauważ, że nie możesz zmienić $ index, zaleca się, aby nie używać $ index zamiast używać identyfikatora unikalnego dla obiektu (np. Id)
ram1993