Wie du die Geschwindigkeit von ngRepeat bei großen Datensätzen super einfach verbessern kannst

Als Webentwickler lernt man recht schnell, dass der DOM in allen Webbrowsern sehr sehr langsam ist. Gerade wenn einen sanftes Scrollen für eine gute User Experience erwünscht ist, sind riesige Datensätze oft ein Problem.

Glücklicherweise gibt es hierfür eine einfache Option in AngularJS. Der einfachste Weg bei großen Mengen von Daten Performanceverluste zu vermeiden ist die Verwendung von Paginierung oder Infinite Scroll, also das „unendliche“ Scrollen, wo automatisch Inhalte nachgeladen werden. In AngularJS gibt es hierfür den Filter `limitTo`.

Wie funktioniert `limitTo`?

Es gibt insgesamt 3 Parameter für diesen Filter: Der Eingabewert (input) und die Limitierung (limit) sind Pflichtangaben. Optional kann der Start-Offset (begin) angegeben werden. Ist dieser negativ, wird der Eingabewert von hinten beginnend beschränkt.

{{ limitTo_expression | limitTo : limit : begin}}

Der Filter kann außerdem auch direkt im JavaScript aufgerufen werden:

$filter('limitTo')(input, limit, begin);

Wie benutzt man den Filter?

Vorausgesetzt ist ein Array mit Elementen, welche wir in einer ungeordneten Liste im HTML ausgeben möchten.

// your angularjs controller:
var vm = this;
vm.myList = [
  {id:1, name:"myItem1", image:"http://placehold.it/350x150"},
  {/* ... many more items ... */}
];

HTML:

<div ng-app="myApp" ng-controller="MyCtrl as vm">
<ul>
 <li ng-repeat="listItem in vm.myList"><img ng-src="{{listItem.image}}" /> {{listItem.id}}: {{listItem.name}}</li>
</ul>
</div>

Das funktioniert, ist aber langsam, wenn zu viele Elemente gleichzeitig auf dem Bildschirm dargestellt werden müssen. Also nutzen wir den Filter `limitTo` innerhalb des ngRepeat-Ausdrucks. Wir möchten aber keinen statischen Wert dort reinschreiben, sondern das ganze dynamisch über eine Variable `total` lösen.

vm.total = 25;

Das HTML sieht nun wie folgt aus:

<ul>
<li ng-repeat="listItem in vm.myList | limitTo:vm.total"><img ng-src="{{listItem.image}}" /> {{listItem.id}}: {{listItem.name}}</li>
</ul>

Abschließend fügen wir noch eine Button am Ende der Liste hinzu, um die Variable `total` hoch zu zählen und so mehr Elemente auf dem Bildschirm auszugeben. Wir könnten das ganze auch automatisiert über die aktuelle Scrollposition auslösen. Der Einfachheit halber löse ich es hier mit einem separatem Button.

vm.loadMoreItems = function(){
vm.total += 25;
};

Das HTML für den Button könnte so aussehen:

<button class="btn btn-primary" ng-click="vm.loadMoreItems()">Load more</button>

Jetzt haben wir eine kleine aber sehr schnelle Liste von Elementen. Möchte der Nutzer mehr Elemente sehen, kann er diese nach und nach anzeigen lassen.

Das komplette JavaScript Beispiel findest du auf CodePen.

Wie kann ich Paginierung in AngularJS umsetzen?

Das Beispiel oben funktioniert soweit und ist am Anfang sehr performant. Aber man bekommt ein Problem, wenn der Nutzer den Button zum Anzeigen weiterer Elemente immer wieder drückt. Dann muss der Webbrowser nämlich doch irgendwann alle Elemente auf einmal darstellen.

Also entscheiden wir uns maximal 10 Elemente je Seite anzuzeigen und verwenden hierfür den von AngularJS bereitgestellten Parameter `begin`.

Wir erhöhen demnach nicht mehr die Gesamtanzahl an sichtbaren Elemente (limit), sondern lediglich den Offset der Startposition in unserem Array:

vm.total = 10;
vm.beginOffset = 0;
vm.loadMoreItems = function() {
  vm.beginOffset += 10;
};

Eine kleine Änderung am HTML:

<li ng-repeat="listItem in vm.myList | limitTo:vm.total:vm.beginOffset"><img ng-src="{{listItem.image}}" /> {{listItem.id}}: {{listItem.name}}</li>

Und wir sind fertig! Das komplette Beispiel mit Paginierung ist ebenfalls bei CodePen.

Quellen:

Weiterempfehlen: