Wie kann die Leistung von ngRepeat über einen großen Datensatz (angle.js) verbessert werden?


165

Ich habe einen riesigen Datensatz von mehreren tausend Zeilen mit jeweils etwa 10 Feldern, ungefähr 2 MB Daten. Ich muss es im Browser anzeigen. Der einfachste Ansatz (Daten abrufen, ablegen $scope, ng-repeat=""erledigen lassen ) funktioniert einwandfrei, friert den Browser jedoch für etwa eine halbe Minute ein, wenn er anfängt, Knoten in DOM einzufügen. Wie soll ich dieses Problem angehen?

Eine Möglichkeit besteht darin, Zeilen $scopeschrittweise anzuhängen und zu warten, ngRepeatbis das Einfügen eines Blocks in das DOM abgeschlossen ist, bevor Sie mit dem nächsten fortfahren. AFAIK ngRepeat meldet sich jedoch nicht zurück, wenn das "Wiederholen" beendet ist, sodass es hässlich wird.

Eine andere Möglichkeit besteht darin, Daten auf dem Server in Seiten aufzuteilen und sie in mehreren Anforderungen abzurufen. Dies ist jedoch noch hässlicher.

Ich habe in der Angular-Dokumentation nach etwas Ähnlichem gesucht ng-repeat="data in dataset" ng-repeat-steps="500", aber nichts gefunden. Ich bin ziemlich neu in Angular-Methoden, daher ist es möglich, dass ich den Punkt komplett verfehle. Was sind die Best Practices dabei?


10
Möchten Sie wirklich ALLE Zeilen anzeigen? Wie wäre es, wenn nur so viele Zeilen angezeigt werden, die der Benutzer sehen kann? Beispiel: Sie können limitTonur 20 Elemente anzeigen: <p ng-repeat="data in dataset | limitTo:20">{{data}}</p>Hier werden nur 20 Elemente angezeigt . Dann könnten Sie Seiten verwenden und die nächsten 10 Elemente oder ähnliches anzeigen. :)
AndreM96

Für diese "Rückmeldung, wenn die Wiederholung beendet ist" können Sie zusätzlich zu ng-repeat eine benutzerdefinierte Direktive verwenden. (siehe hier die ausgewählte Antwort) stackoverflow.com/questions/13471129/…
mayankcpdixit

Verweisen Sie auf diese Frage, es wird Ihnen sicherlich helfen. [ Linkbeschreibung
Mahesh

Antworten:


159

Ich stimme @ AndreM96 zu, dass der beste Ansatz darin besteht, nur eine begrenzte Anzahl von Zeilen anzuzeigen, schneller und besser UX. Dies könnte mit einer Paginierung oder mit einer unendlichen Schriftrolle erfolgen.

Infinite Scroll mit Angular ist mit dem LimitTo- Filter wirklich einfach . Sie müssen nur das anfängliche Limit festlegen und wenn der Benutzer weitere Daten anfordert (ich verwende der Einfachheit halber eine Schaltfläche), erhöhen Sie das Limit.

<table>
    <tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>

//the controller
$scope.totalDisplayed = 20;

$scope.loadMore = function () {
  $scope.totalDisplayed += 20;  
};

$scope.data = data;

Hier ist ein JsBin .

Dieser Ansatz könnte für Telefone ein Problem sein, da sie normalerweise beim Scrollen vieler Daten zurückbleiben. In diesem Fall passt eine Paginierung meiner Meinung nach besser.

Dazu benötigen Sie den Filter limitTo sowie einen benutzerdefinierten Filter, um den Startpunkt der angezeigten Daten zu definieren.

Hier ist ein JSBin mit einer Paginierung.


Schöne Alternative !!! Sie kennen jede Methode, wenn ich verpflichtet bin, alle Elemente anzuzeigen. irgendein Ladeschild oder eins nach dem anderen in DOM oder so?
Mayankcpdixit

Meinen Sie damit ein "Laden ..." oder etwas, während die Daten abgerufen werden?
Bertrand

1
@Sumit limitTo wird auf den Bereich ng-repeat angewendet, sodass das Ergebnis ein neues Array ist, das an ng-repeat übergeben wird. Ihr Datenarray bleibt unverändert, und Sie können weiterhin den gesamten Inhalt durchsuchen.
Bertrand

12
Wie kann die Leistung verbessert werden, wenn der Benutzer mehr als 10 Mal auf load drückt und bei jedem Drücken 100 weitere Elemente hinzugefügt werden?
Hariszaman

5
@hariszaman Ich stimme zu. Dies verbessert die Leistung nicht. Es verzögert nur die schlechte Leistung. Infinite Scroll bringt Sie in Schwierigkeiten, es sei denn, Sie virtualisieren es (was ui-grid tut).
Richard

41

Der heißeste - und wohl skalierbarste - Ansatz zur Überwindung dieser Herausforderungen mit großen Datenmengen ist der Ansatz der collectionRepeat-Direktive von Ionic und anderer Implementierungen wie dieser. Ein ausgefallener Begriff dafür ist "Okklusions-Culling" , aber Sie können es wie folgt zusammenfassen: Beschränken Sie die Anzahl der gerenderten DOM-Elemente nicht nur auf eine beliebige (aber immer noch hohe) paginierte Zahl wie 50, 100, 500 ... stattdessen , Limit nur so viele Elemente wie der Benutzer zu sehen .

Wenn Sie so etwas wie das sogenannte "unendliche Scrollen" ausführen , reduzieren Sie die anfängliche DOM-Anzahl etwas, aber sie bläht sich nach ein paar Aktualisierungen schnell auf, da all diese neuen Elemente nur unten angeheftet werden. Das Scrollen kommt zu einem Crawl, da es beim Scrollen nur um die Anzahl der Elemente geht. Es ist nichts Unendliches daran.

Der collectionRepeatAnsatz besteht darin, nur so viele Elemente zu verwenden, wie in das Ansichtsfenster passen, und diese dann zu recyceln . Wenn ein Element nicht mehr sichtbar ist, wird es vom Renderbaum getrennt, mit Daten für ein neues Element in der Liste gefüllt und dann am anderen Ende der Liste wieder mit dem Renderbaum verbunden. Dies ist der schnellste Weg, den der Mensch kennt, um neue Informationen in das DOM und aus dem DOM heraus zu erhalten, wobei eine begrenzte Anzahl vorhandener Elemente verwendet wird und nicht der traditionelle Zyklus von Erstellen / Zerstören ... Erstellen / Zerstören. Mit diesem Ansatz können Sie wirklich eine unendliche Schriftrolle implementieren .

Beachten Sie, dass Sie Ionic nicht verwenden müssen, um / hack / adapt collectionRepeatoder ein anderes Tool wie dieses zu verwenden. Deshalb nennen sie es Open Source. :-) (Das heißt, das Ionic-Team macht einige ziemlich geniale Dinge, die Ihrer Aufmerksamkeit wert sind.)


Es gibt mindestens einen hervorragendes Beispiel dafür, wie man in React etwas sehr Ähnliches macht. Nur anstatt die Elemente mit aktualisiertem Inhalt zu recyceln, entscheiden Sie sich einfach dafür, nichts in der Baumstruktur zu rendern, was nicht angezeigt wird. Bei 5000 Artikeln ist es blitzschnell, obwohl die sehr einfache POC-Implementierung ein bisschen Flimmern zulässt ...


Auch ... um einige der anderen Beiträge wiederzugeben, ist die Verwendung sehr track byhilfreich, selbst bei kleineren Datensätzen. Betrachten Sie es als obligatorisch.


Tolle Idee vom Ionic-Team. Ich frage mich, ob das darauf zurückzuführen ist, wie native Ansichten gerendert werden.
Bradley Flood

Beispielsweise verwendet UITableView in iOS denselben Ansatz zum Rendern großer Datenmengen. Ich denke, dies ist ein gängiger Ansatz, der in vielen nativen Ansichten verwendet wird.
Dmitry Kotenko

36

Ich empfehle dies zu sehen:

AngularJS optimieren: 1200 ms bis 35 ms

Sie haben eine neue Richtlinie erstellt, indem sie ng-repeat in 4 Teilen optimiert haben:

Optimierung Nr. 1: DOM-Elemente zwischenspeichern

Optimierung Nr. 2: Aggregierte Beobachter

Optimierung Nr. 3: Verschieben der Elementerstellung

Optimierung Nr. 4: Bypass-Beobachter für versteckte Elemente

Das Projekt ist hier auf Github:

Verwendung:

1- Fügen Sie diese Dateien in Ihre einseitige App ein:

  • core.js
  • scalyr.js
  • slyEvaluate.js
  • slyRepeat.js

2- Modulabhängigkeit hinzufügen:

var app = angular.module("app", ['sly']);

3- ng-repeat ersetzen

<tr sly-repeat="m in rows"> .....<tr>

Genießen!


4
Ich denke, diese scalyr.js enthält bereits die anderen Dateien. Weil ist das Ergebnis des Build-Skripts.
Dnocode

Ich habe versucht, Scalyr zu verwenden, aber der Filter funktioniert nicht. <tr sly-repeat = "Option in main.customers | filter: search_input | limitTo: 20">
aldesabido

Das ist sehr hilfreich. Ich verwende es in einer AngularJS 1.6-App, in der der Client viele Datenzellen sehen möchte (normalerweise entwerfe ich Formulare mit Paging / reduzierten Datenelementen, aber der Client muss viele Daten gleichzeitig vergleichen). Bisher ist das Zellenraster aufgrund dieser Bibliothek von unbrauchbar zu vollkommen fein geworden. Aber diese Bibliothek wurde bereits vor 1,2 Tagen in AngularJS geschrieben, daher werde ich sorgfältig nach Problemen suchen.
Flyer

Nach dem, was ich derzeit sagen kann, ist die Datei gatedScope.js (323 Zeilen) die einzige, die überprüft werden muss, um auf aktuelleren Versionen von AngularJS ausgeführt werden zu können. Diese Pull-Anfrage ist bemerkenswert: github.com/karser/angular/commit/… . Es aktualisiert die Signatur rootScope. $ New.
Flyer

schloss alle vier js-Dateien ein und benutzte, sly-repeataber nichts half mir, die Ergebnisse sind immer noch langsam und Browser-Verzögerungen bekommen auch Verstöße [Violation] 'setTimeout' handler took 54ms,[Violation] 'scroll' handler took 1298ms
Gaurav Aggarwal

15

Neben all den oben genannten Hinweisen wie Track by und kleineren Loops hat mir dieser auch sehr geholfen

<span ng-bind="::stock.name"></span>

Dieser Code druckt den Namen, sobald er geladen wurde, und hört danach auf, ihn anzusehen. In ähnlicher Weise könnte es für ng-Wiederholungen als verwendet werden

<div ng-repeat="stock in ::ctrl.stocks">{{::stock.name}}</div>

Es funktioniert jedoch nur für AngularJS Version 1.3 und höher. Von http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/


Benötigen Sie sowohl ::die Wiederholung als auch den Ausdruck? Die Dokumente sagen etwas anderes, aber ich bin mir nicht sicher, wie ich testen kann, ob dies funktioniert. docs.angularjs.org/guide/expression
Crhistian Ramirez

12

Sie können "Track by" verwenden, um die Leistung zu steigern:

<div ng-repeat="a in arr track by a.trackingKey">

Schneller als:

<div ng-repeat="a in arr">

Ref: https://www.airpair.com/angularjs/posts/angularjs-performance-large-applications


1
Dies hilft nicht wirklich für die Leistung. Siehe jsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
ilter

Mit track by verfolgen Sie das Array-Element nicht jedes Mal von Anfang an, wenn Sie neue Daten erhalten. Infolgedessen verbessert dies die Leistung.
user1920302

2
Dies ist nur nützlich, wenn sich die Daten in der ng-Wiederholung ändern. Beim erstmaligen Laden wird möglicherweise keine Leistungsverbesserung erzielt.
Sumesh Kuttan

11

Wenn alle Ihre Zeilen gleich hoch sind, sollten Sie sich unbedingt die virtualisierende ng-repeat ansehen: http://kamilkp.github.io/angular-vs-repeat/

Diese Demo sieht sehr vielversprechend aus (und unterstützt das Trägheits-Scrollen)


2
Die Bildlaufleistung auf Mobilgeräten ist nicht akzeptabel (Bildlaufereignisse werden auf Mobilgeräten mit iOS nicht ausgelöst (nur ab 8)
Johny,

9

Regel Nr. 1: Lassen Sie den Benutzer niemals auf etwas warten.

In Anbetracht dessen erscheint eine lebenswachsende Seite, die 10 Sekunden benötigt, viel schneller als 3 Sekunden vor einem leeren Bildschirm zu warten und alles auf einmal zu erhalten.

Anstatt also make schnell die Seite, lassen Sie einfach die Seite erscheinen , schnell zu sein, auch wenn das Endergebnis ist langsamer:

function applyItemlist(items){
    var item = items.shift();
    if(item){
        $timeout(function(){
            $scope.items.push(item);
            applyItemlist(items);
        }, 0); // <-- try a little gap of 10ms
    }
}

Der obige Code lässt die Liste zeilenweise wachsen und ist immer langsamer als das gleichzeitige Rendern. Aber für den Benutzer scheint es schneller zu sein.


Wie verwende ich diese Funktion auf einer HTML-Seite?
Antonis

9

Virtuelles Scrollen ist eine weitere Möglichkeit, die Bildlaufleistung bei großen Listen und großen Datenmengen zu verbessern.

Eine Möglichkeit, dies zu implementieren, ist die Verwendung von Angular Material, md-virtual-repeat wie in dieser Demo mit 50.000 Elementen gezeigt

Entnommen direkt aus der Dokumentation der virtuellen Wiederholung:

Die virtuelle Wiederholung ist ein begrenzter Ersatz für ng-repeat, bei dem nur genügend Dom-Knoten gerendert werden, um den Container zu füllen und sie beim Scrollen des Benutzers zu recyceln.


2
Wow, ich denke das ist die interessanteste Antwort. Funktioniert dies mit älteren Versionen von Angular? (zB
Version

2
@ThariqNugrohotomo Bitte beachten Sie, dass für die Verwendung von Angular Material Angular 1.3.x oder höher erforderlich ist. Vielen Dank auch für die Unterstützung. Ich bin auch sehr erstaunt über die virtuelle Wiederholung und wir verwenden sie bereits in einer mobilen App, die eine sehr lange Liste von Ergebnissen anzeigt.
Sarantis Tofas

6

Eine andere Version @Steffomio

Anstatt jedes Element einzeln hinzuzufügen, können wir Elemente nach Stücken hinzufügen.

// chunks function from here: 
// http://stackoverflow.com/questions/8495687/split-array-into-chunks#11764168
var chunks = chunk(folders, 100);

//immediate display of our first set of items
$scope.items = chunks[0];

var delay = 100;
angular.forEach(chunks, function(value, index) {
    delay += 100;

    // skip the first chuck
    if( index > 0 ) {
        $timeout(function() {
            Array.prototype.push.apply($scope.items,value);
        }, delay);
    }       
});

Interessante Idee. Ich habe dies an einem Array von ~ 8000 Elementen versucht, und obwohl die Seite anfangs reaktionsfähiger wurde, wurde sie nach jedem Block weniger reaktionsschnell.
Paul Brannan

Dies war ein großes Problem in meiner App, nachdem ich mehr als 500 Artikel hatte. Ich schlage stattdessen Paginierung oder unendliches Laden vor.
Joalcego

0

Manchmal, was passiert ist, erhalten Sie die Daten vom Server (oder Back-End) in wenigen ms (ich gehe beispielsweise davon aus, dass es 100 ms sind), aber die Anzeige auf unserer Webseite dauert länger (sagen wir, es dauert 900 ms bis Anzeige).

Was hier passiert, sind 800 ms. Es dauert nur, um eine Webseite zu rendern.

Was ich in meiner Webanwendung getan habe, ist, dass ich Paginierung verwendet habe (oder Sie können unendliches Scrollen verwenden ), um eine Liste von Daten anzuzeigen. Angenommen, ich zeige 50 Daten / Seite.

Ich werde also nicht alle Daten auf einmal laden, sondern nur 50 Daten, die ich anfänglich lade, was nur 50 ms dauert (ich gehe hier davon aus).

Die Gesamtzeit wurde hier von 900 ms auf 150 ms verringert. Sobald der Benutzer die nächste Seite angefordert hat, werden die nächsten 50 Daten angezeigt und so weiter.

Ich hoffe, dies wird Ihnen helfen, die Leistung zu verbessern. Alles Gute


0
Created a directive (ng-repeat with lazy loading) 

Dies lädt Daten, wenn es bis zum Ende der Seite reicht und die Hälfte der zuvor geladenen Daten entfernt, und wenn es wieder bis zum oberen Rand des Div reicht. Vorherige Daten (abhängig von der Seitenzahl) werden geladen, wobei die Hälfte der aktuellen Daten entfernt wird. Also auf DOM Zu einem Zeitpunkt sind nur begrenzte Daten vorhanden, was zu einer besseren Leistung führen kann, anstatt ganze Daten beim Laden zu rendern.

HTML QUELLTEXT:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
  <div class="row customScroll" id="customTable" datafilter pagenumber="pageNumber" data="rowData" searchdata="searchdata" itemsPerPage="{{itemsPerPage}}"  totaldata="totalData"   selectedrow="onRowSelected(row,row.index)"  style="height:300px;overflow-y: auto;padding-top: 5px">

    <!--<div class="col-md-12 col-xs-12 col-sm-12 assign-list" ng-repeat="row in CRGC.rowData track by $index | orderBy:sortField:sortReverse | filter:searchFish">-->
    <div class="col-md-12 col-xs-12 col-sm-12 pdl0 assign-list" style="padding:10px" ng-repeat="row in rowData" ng-hide="row[CRGC.columns[0].id]=='' && row[CRGC.columns[1].id]==''">
        <!--col1-->

        <div ng-click ="onRowSelected(row,row.index)"> <span>{{row["sno"]}}</span> <span>{{row["id"]}}</span> <span>{{row["name"]}}</span></div>
      <!--   <div class="border_opacity"></div> -->
    </div>

</div>

  </body>

</html>

Winkelcode:

var app = angular.module('plunker', []);
var x;
ListController.$inject = ['$scope', '$timeout', '$q', '$templateCache'];

function ListController($scope, $timeout, $q, $templateCache) {
  $scope.itemsPerPage = 40;
  $scope.lastPage = 0;
  $scope.maxPage = 100;
  $scope.data = [];
  $scope.pageNumber = 0;


  $scope.makeid = function() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 5; i++)
      text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
  }


  $scope.DataFormFunction = function() {
      var arrayObj = [];
      for (var i = 0; i < $scope.itemsPerPage*$scope.maxPage; i++) {
          arrayObj.push({
              sno: i + 1,
              id: Math.random() * 100,
              name: $scope.makeid()
          });
      }
      $scope.totalData = arrayObj;
      $scope.totalData = $scope.totalData.filter(function(a,i){ a.index = i; return true; })
      $scope.rowData = $scope.totalData.slice(0, $scope.itemsperpage);
    }
  $scope.DataFormFunction();

  $scope.onRowSelected = function(row,index){
    console.log(row,index);
  }

}

angular.module('plunker').controller('ListController', ListController).directive('datafilter', function($compile) {
  return {
    restrict: 'EAC',
    scope: {
      data: '=',
      totalData: '=totaldata',
      pageNumber: '=pagenumber',
      searchdata: '=',
      defaultinput: '=',
      selectedrow: '&',
      filterflag: '=',
      totalFilterData: '='
    },
    link: function(scope, elem, attr) {
      //scope.pageNumber = 0;
      var tempData = angular.copy(scope.totalData);
      scope.totalPageLength = Math.ceil(scope.totalData.length / +attr.itemsperpage);
      console.log(scope.totalData);
      scope.data = scope.totalData.slice(0, attr.itemsperpage);
      elem.on('scroll', function(event) {
        event.preventDefault();
      //  var scrollHeight = angular.element('#customTable').scrollTop();
      var scrollHeight = document.getElementById("customTable").scrollTop
        /*if(scope.filterflag && scope.pageNumber != 0){
        scope.data = scope.totalFilterData;
        scope.pageNumber = 0;
        angular.element('#customTable').scrollTop(0);
        }*/
        if (scrollHeight < 100) {
          if (!scope.filterflag) {
            scope.scrollUp();
          }
        }
        if (angular.element(this).scrollTop() + angular.element(this).innerHeight() >= angular.element(this)[0].scrollHeight) {
          console.log("scroll bottom reached");
          if (!scope.filterflag) {
            scope.scrollDown();
          }
        }
        scope.$apply(scope.data);

      });

      /*
       * Scroll down data append function
       */
      scope.scrollDown = function() {
          if (scope.defaultinput == undefined || scope.defaultinput == "") { //filter data append condition on scroll
            scope.totalDataCompare = scope.totalData;
          } else {
            scope.totalDataCompare = scope.totalFilterData;
          }
          scope.totalPageLength = Math.ceil(scope.totalDataCompare.length / +attr.itemsperpage);
          if (scope.pageNumber < scope.totalPageLength - 1) {
            scope.pageNumber++;
            scope.lastaddedData = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage, (+attr.itemsperpage) + (+scope.pageNumber * attr.itemsperpage));
            scope.data = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage - 0.5 * (+attr.itemsperpage), scope.pageNumber * attr.itemsperpage);
            scope.data = scope.data.concat(scope.lastaddedData);
            scope.$apply(scope.data);
            if (scope.pageNumber < scope.totalPageLength) {
              var divHeight = $('.assign-list').outerHeight();
              if (!scope.moveToPositionFlag) {
                angular.element('#customTable').scrollTop(divHeight * 0.5 * (+attr.itemsperpage));
              } else {
                scope.moveToPositionFlag = false;
              }
            }


          }
        }
        /*
         * Scroll up data append function
         */
      scope.scrollUp = function() {
          if (scope.defaultinput == undefined || scope.defaultinput == "") { //filter data append condition on scroll
            scope.totalDataCompare = scope.totalData;
          } else {
            scope.totalDataCompare = scope.totalFilterData;
          }
          scope.totalPageLength = Math.ceil(scope.totalDataCompare.length / +attr.itemsperpage);
          if (scope.pageNumber > 0) {
            this.positionData = scope.data[0];
            scope.data = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage - 0.5 * (+attr.itemsperpage), scope.pageNumber * attr.itemsperpage);
            var position = +attr.itemsperpage * scope.pageNumber - 1.5 * (+attr.itemsperpage);
            if (position < 0) {
              position = 0;
            }
            scope.TopAddData = scope.totalDataCompare.slice(position, (+attr.itemsperpage) + position);
            scope.pageNumber--;
            var divHeight = $('.assign-list').outerHeight();
            if (position != 0) {
              scope.data = scope.TopAddData.concat(scope.data);
              scope.$apply(scope.data);
              angular.element('#customTable').scrollTop(divHeight * 1 * (+attr.itemsperpage));
            } else {
              scope.data = scope.TopAddData;
              scope.$apply(scope.data);
              angular.element('#customTable').scrollTop(divHeight * 0.5 * (+attr.itemsperpage));
            }
          }
        }
    }
  };
});

Demo mit Direktive

Another Solution: If you using UI-grid in the project then  same implementation is there in UI grid with infinite-scroll.

Abhängig von der Höhe der Teilung werden die Daten geladen und beim Scrollen werden neue Daten angehängt und vorherige Daten werden entfernt.

HTML Quelltext:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css" type="text/css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.6/ui-grid.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
     <div class="input-group" style="margin-bottom: 15px">
      <div class="input-group-btn">
        <button class='btn btn-primary' ng-click="resetList()">RESET</button>
      </div>
      <input class="form-control" ng-model="search" ng-change="abc()">
    </div>

    <div data-ui-grid="gridOptions" class="grid" ui-grid-selection  data-ui-grid-infinite-scroll style="height :400px"></div>

    <button ng-click="getProductList()">Submit</button>
  </body>

</html>

Winkelcode:

var app = angular.module('plunker', ['ui.grid', 'ui.grid.infiniteScroll', 'ui.grid.selection']);
var x;
angular.module('plunker').controller('ListController', ListController);
ListController.$inject = ['$scope', '$timeout', '$q', '$templateCache'];

function ListController($scope, $timeout, $q, $templateCache) {
    $scope.itemsPerPage = 200;
    $scope.lastPage = 0;
    $scope.maxPage = 5;
    $scope.data = [];

    var request = {
        "startAt": "1",
        "noOfRecords": $scope.itemsPerPage
    };
    $templateCache.put('ui-grid/selectionRowHeaderButtons',
        "<div class=\"ui-grid-selection-row-header-buttons \" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ><input style=\"margin: 0; vertical-align: middle\" type=\"checkbox\" ng-model=\"row.isSelected\" ng-click=\"row.isSelected=!row.isSelected;selectButtonClick(row, $event)\">&nbsp;</div>"
    );


    $templateCache.put('ui-grid/selectionSelectAllButtons',
        "<div class=\"ui-grid-selection-row-header-buttons \" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-if=\"grid.options.enableSelectAll\"><input style=\"margin: 0; vertical-align: middle\" type=\"checkbox\" ng-model=\"grid.selection.selectAll\" ng-click=\"grid.selection.selectAll=!grid.selection.selectAll;headerButtonClick($event)\"></div>"
    );

    $scope.gridOptions = {
        infiniteScrollDown: true,
        enableSorting: false,
        enableRowSelection: true,
        enableSelectAll: true,
        //enableFullRowSelection: true,
        columnDefs: [{
            field: 'sno',
            name: 'sno'
        }, {
            field: 'id',
            name: 'ID'
        }, {
            field: 'name',
            name: 'My Name'
        }],
        data: 'data',
        onRegisterApi: function(gridApi) {
            gridApi.infiniteScroll.on.needLoadMoreData($scope, $scope.loadMoreData);
            $scope.gridApi = gridApi;
        }
    };
    $scope.gridOptions.multiSelect = true;
    $scope.makeid = function() {
        var text = "";
        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        for (var i = 0; i < 5; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));

        return text;
    }
    $scope.abc = function() {
        var a = $scope.search;
        x = $scope.searchData;
        $scope.data = x.filter(function(arr, y) {
            return arr.name.indexOf(a) > -1
        })
        console.log($scope.data);
        if ($scope.gridApi.grid.selection.selectAll)
            $timeout(function() {
                $scope.gridApi.selection.selectAllRows();
            }, 100);
    }


    $scope.loadMoreData = function() {
        var promise = $q.defer();
        if ($scope.lastPage < $scope.maxPage) {
            $timeout(function() {
                var arrayObj = [];
                for (var i = 0; i < $scope.itemsPerPage; i++) {
                    arrayObj.push({
                        sno: i + 1,
                        id: Math.random() * 100,
                        name: $scope.makeid()
                    });
                }

                if (!$scope.search) {
                    $scope.lastPage++;
                    $scope.data = $scope.data.concat(arrayObj);
                    $scope.gridApi.infiniteScroll.dataLoaded();
                    console.log($scope.data);
                    $scope.searchData = $scope.data;
                    // $scope.data = $scope.searchData;
                    promise.resolve();
                    if ($scope.gridApi.grid.selection.selectAll)
                        $timeout(function() {
                            $scope.gridApi.selection.selectAllRows();
                        }, 100);
                }


            }, Math.random() * 1000);
        } else {
            $scope.gridApi.infiniteScroll.dataLoaded();
            promise.resolve();
        }
        return promise.promise;
    };

    $scope.loadMoreData();

    $scope.getProductList = function() {

        if ($scope.gridApi.selection.getSelectedRows().length > 0) {
            $scope.gridOptions.data = $scope.resultSimulatedData;
            $scope.mySelectedRows = $scope.gridApi.selection.getSelectedRows(); //<--Property undefined error here
            console.log($scope.mySelectedRows);
            //alert('Selected Row: ' + $scope.mySelectedRows[0].id + ', ' + $scope.mySelectedRows[0].name + '.');
        } else {
            alert('Select a row first');
        }
    }
    $scope.getSelectedRows = function() {
        $scope.mySelectedRows = $scope.gridApi.selection.getSelectedRows();
    }
    $scope.headerButtonClick = function() {

        $scope.selectAll = $scope.grid.selection.selectAll;

    }
}

Demo mit UI-Raster mit Infinite-Scroll-Demo


Ein Link zu einer Lösung ist willkommen, aber stellen Sie bitte sicher, dass Ihre Antwort ohne sie nützlich ist: Fügen Sie dem Link einen Kontext hinzu, damit Ihre Mitbenutzer eine Vorstellung davon haben, was es ist und warum es dort ist, und zitieren Sie dann den relevantesten Teil der Seite, die Sie verwenden. erneutes Verknüpfen mit, falls die Zielseite nicht verfügbar ist. Antworten, die kaum mehr als ein Link sind, können gelöscht werden .
Am 8.

-2

Für große Datenmengen und Dropdown-Listen mit mehreren Werten ist es besser, diese zu verwenden ng-optionsals ng-repeat.

ng-repeatist langsam, da alle kommenden Werte durchlaufen werden, aber ng-optionseinfach zur Auswahloption angezeigt wird.

ng-options='state.StateCode as state.StateName for state in States'>

viel viel schneller als

<option ng-repeat="state in States" value="{{state.StateCode}}">
    {{state.StateName }}
</option>

Haben Sie die Leistung von ng-options überprüft? Ich versuche meinen Code zu optimieren und es hat nicht geholfen. Die Geschwindigkeit ist die gleiche wie bei ng-repeat. -1
Icet

funktioniert nur für select, ng-repeat ist viel leistungsfähiger. Trotzdem ist ng-Options viel schneller als ng-repeat. AngularJS docs erwähnt 2000 Artikel für Unterschiede: docs.angularjs.org/api/ng/directive/select
kaiser
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.