Bagaimana cara meningkatkan kinerja ngRepeat melalui dataset besar (angular.js)?

165

Saya memiliki dataset besar beberapa ribu baris dengan masing-masing sekitar 10 bidang, sekitar 2MB data. Saya perlu menampilkannya di browser. Pendekatan yang paling mudah (mengambil data, memasukkannya $scope, ng-repeat=""melakukan tugasnya) berfungsi dengan baik, tetapi membeku browser selama sekitar setengah menit ketika mulai memasukkan node ke DOM. Bagaimana saya harus mendekati masalah ini?

Salah satu opsi adalah menambahkan baris $scopesecara bertahap dan menunggu untuk ngRepeatmenyelesaikan memasukkan satu chunk ke DOM sebelum pindah ke yang berikutnya. Tapi AFAIK ngRepeat tidak melaporkan kembali ketika selesai "berulang", jadi itu akan menjadi jelek.

Pilihan lain adalah untuk membagi data pada server menjadi beberapa halaman dan mengambilnya dalam beberapa permintaan, tetapi itu lebih buruk.

Saya melihat melalui dokumentasi Angular untuk mencari sesuatu seperti ng-repeat="data in dataset" ng-repeat-steps="500", tetapi tidak menemukan apa pun. Saya cukup baru dalam cara Angular, jadi ada kemungkinan bahwa saya kehilangan poin sepenuhnya. Apa praktik terbaik dalam hal ini?

n1313
sumber
10
Apakah Anda benar-benar ingin menampilkan SEMUA baris? Bagaimana dengan hanya menampilkan banyak baris yang dapat dilihat pengguna. mis. Anda dapat menggunakan limitTountuk menampilkan hanya 20 item: <p ng-repeat="data in dataset | limitTo:20">{{data}}</p>Ini hanya menampilkan 20 item. Kemudian Anda dapat menggunakan halaman dan menunjukkan 10 item berikutnya atau sesuatu seperti itu. :)
AndreM96
untuk itu "laporkan kembali ketika selesai 'mengulangi'" hal yang Anda bisa menggunakan arahan khusus selain ng-ulangi. (lihat di sini jawaban yang dipilih) stackoverflow.com/questions/13471129/…
mayankcpdixit
lihat pertanyaan ini pasti akan membantu Anda. [masukkan uraian tautan di sini] [1] [1]: stackoverflow.com/questions/25481021/…
Mahesh

Jawaban:

159

Saya setuju dengan @ AndreM96 bahwa pendekatan terbaik adalah hanya menampilkan jumlah baris terbatas, UX lebih cepat dan lebih baik, ini bisa dilakukan dengan pagination atau dengan scroll tak terbatas.

Scroll tanpa batas dengan Angular sangat sederhana dengan filter limitTo . Anda hanya perlu menetapkan batas awal dan ketika pengguna meminta lebih banyak data (saya menggunakan tombol untuk kesederhanaan) Anda menambah batas.

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

Ini JsBin .

Pendekatan ini bisa menjadi masalah bagi ponsel karena biasanya mereka tertinggal ketika menggulir banyak data, jadi dalam hal ini saya pikir pagination lebih cocok.

Untuk melakukannya, Anda akan memerlukan filter limitTo dan juga filter khusus untuk menentukan titik awal dari data yang ditampilkan.

Ini JSBin dengan pagination.

Bertrand
sumber
Alternatif yang bagus !!! Anda tahu metode apa pun untuk digunakan jika saya harus menunjukkan semua item. ada tanda memuat atau satu setelah satu penyisipan ke DOM atau sesuatu?
mayankcpdixit
Apakah maksud Anda menampilkan "memuat ..." atau sesuatu saat data diambil?
Bertrand
1
@Sumit limitTo akan diterapkan ke lingkup ng-repeat, sehingga hasilnya akan menjadi array baru yang akan diteruskan ke ng-repeat, array data Anda masih sama dan Anda masih dapat mencari semua konten.
Bertrand
12
jika pengguna menekan memuat lebih dari 10 kali dan setiap pers menambahkan 100 item lagi, bagaimana ini dapat meningkatkan kinerja?
hariszaman
5
@ hariszaman saya setuju. Ini tidak meningkatkan kinerja. Itu hanya menunda kinerja yang buruk. Scroll tak terbatas akan membuat Anda mendapat masalah kecuali Anda memvirtualisasikannya (yang mana ui-grid lakukan).
richard
41

Pendekatan terpanas - dan bisa dibilang paling scalable - untuk mengatasi tantangan ini dengan dataset besar diwujudkan dengan pendekatan directive collectionRepeat directive dan implementasi lain seperti itu. Istilah mewah untuk ini adalah 'penyumbatan oklusi' , tetapi Anda dapat meringkasnya sebagai: jangan hanya membatasi jumlah elemen DOM yang diberikan ke nomor paginasi acak (tapi masih tinggi) seperti 50, 100, 500 ... sebagai gantinya , batasi hanya elemen sebanyak yang dapat dilihat pengguna .

Jika Anda melakukan sesuatu seperti apa yang umumnya dikenal sebagai "pengguliran tak terbatas", Anda mengurangi jumlah DOM awal , tetapi cepat menggembung setelah beberapa penyegaran, karena semua elemen baru itu hanya ditempel di bagian bawah. Pengguliran datang ke perayapan, karena pengguliran adalah tentang jumlah elemen. Tidak ada yang tak terbatas tentang itu.

Padahal, collectionRepeatpendekatannya adalah menggunakan elemen sebanyak yang sesuai dengan viewport, dan kemudian mendaur ulangnya . Ketika satu elemen berputar keluar dari pandangan, itu terlepas dari pohon render, diisi ulang dengan data untuk item baru dalam daftar, lalu disambungkan kembali ke pohon render di ujung lain daftar. Ini adalah cara tercepat yang diketahui manusia untuk mendapatkan informasi baru masuk dan keluar dari DOM, memanfaatkan serangkaian elemen yang ada, daripada siklus tradisional buat / hancurkan ... buat / hancurkan. Dengan menggunakan pendekatan ini, Anda dapat benar-benar menerapkan gulir yang tak terbatas .

Perhatikan bahwa Anda tidak harus menggunakan Ionic untuk menggunakan / hack / adapt collectionRepeat, atau alat lain yang seperti itu. Itu sebabnya mereka menyebutnya open-source. :-) (Konon, tim Ionic melakukan beberapa hal yang cukup cerdik, layak mendapat perhatian Anda.)


Setidaknya ada satu contoh bagus untuk melakukan sesuatu yang sangat mirip di Bereaksi. Hanya alih-alih mendaur ulang elemen dengan konten yang diperbarui, Anda hanya memilih untuk tidak membuat apa pun di pohon yang tidak terlihat. Ini berkobar cepat pada 5000 item, meskipun implementasi POC yang sangat sederhana memungkinkan sedikit ...


Juga ... untuk menggemakan beberapa pos lainnya, menggunakan track bysangat membantu, bahkan dengan kumpulan data yang lebih kecil. Anggap itu wajib.

XML
sumber
Ide yang luar biasa dari tim Ionic. Saya ingin tahu apakah itu berasal dari bagaimana tampilan asli dibuat?
Bradley Flood
Misalnya, UITableView di iOS menggunakan pendekatan yang sama untuk merender set data besar. Saya pikir ini adalah pendekatan umum yang digunakan dalam banyak pandangan asli.
Dmitry Kotenko
36

Saya merekomendasikan untuk melihat ini:

Mengoptimalkan AngularJS: 1200ms hingga 35ms

mereka membuat arahan baru dengan mengoptimalkan ng-repeat di 4 bagian:

Optimalisasi # 1: Elemen DOM cache

Optimasi # 2: Pengamat agregat

Optimasi # 3: Tunda pembuatan elemen

Optimasi # 4: Lewati pengamat untuk elemen tersembunyi

proyeknya ada di github:

Pemakaian:

1- sertakan file-file ini dalam aplikasi satu halaman Anda:

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

2- menambah ketergantungan modul:

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

3- ganti ng-repeat

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

Nikmati!

pixparker
sumber
4
Saya pikir scalyr.js ini sudah termasuk file yang lain. Karena merupakan hasil build script.
dnocode
Saya mencoba menggunakan Scalyr tetapi filter tidak berfungsi. <tr sly-repeat = "option di main.customers | filter: search_input | limitTo: 20">
aldesabido
Ini sangat membantu. Saya menggunakannya pada aplikasi AngularJS 1.6 di mana klien ingin melihat banyak sel data (biasanya saya mendesain formulir dengan paging / elemen data yang dikurangi tetapi klien perlu membandingkan banyak data sekaligus). Sejauh ini grid sel telah berubah dari tidak dapat digunakan menjadi sangat baik karena perpustakaan ini. Tapi lib ini ditulis jauh di AngularJS 1.2 hari jadi saya akan menguji dengan cermat mencari masalah.
brosur
Dari apa yang saya tahu saat ini file gatedScope.js (323 baris) adalah satu-satunya yang perlu diverifikasi agar dapat dijalankan pada versi AngularJS yang lebih baru. Permintaan tarikan ini terkenal: github.com/karser/angular/commit/… . Ini memperbarui rootScope tanda tangan. $ Baru.
flyer
termasuk semua empat file js dan digunakan sly-repeattetapi tidak ada yang membantu saya hasilnya masih lambat dan lag browser juga mendapatkan pelanggaran [Violation] 'setTimeout' handler took 54ms,[Violation] 'scroll' handler took 1298ms
Gaurav Aggarwal
15

Selain semua petunjuk di atas seperti track by dan loop yang lebih kecil, yang ini juga banyak membantu saya

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

sepotong kode ini akan mencetak nama setelah dimuat, dan berhenti menontonnya setelah itu. Demikian pula, untuk ng-pengulangan, itu bisa digunakan sebagai

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

Namun itu hanya bekerja untuk AngularJS versi 1.3 dan lebih tinggi. Dari http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/

Shilan
sumber
Apakah Anda memerlukan ::pengulangan dan ekspresi? Dokumen mengatakan sebaliknya, tetapi saya tidak yakin cara untuk menguji apakah ini berfungsi. docs.angularjs.org/guide/expression
Crhistian Ramirez
12

Anda dapat menggunakan "lacak dengan" untuk meningkatkan kinerja:

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

Lebih cepat dari:

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

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

pengguna1920302
sumber
1
Ini tidak terlalu membantu kinerja. Lihat jsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
ilter
dengan track by Anda tidak melacak elemen array dari awal setiap kali Anda mendapatkan data baru. sebagai hasilnya ini meningkatkan kinerja.
user1920302
2
Ini hanya berguna ketika data di ng-repeat berubah. Untuk muatan awal, ini mungkin tidak membuat peningkatan kinerja.
Sumesh Kuttan
11

Jika semua baris Anda memiliki ketinggian yang sama, Anda harus melihat virtualisasi ng-repeat: http://kamilkp.github.io/angular-vs-repeat/

Demo ini terlihat sangat menjanjikan (dan mendukung pengguliran inersia)

Bartekp
sumber
2
Kinerja gulir di ponsel tidak dapat diterima (acara gulir tidak menyala di iOS seluler (hanya dari 8)
Johny
9

Aturan No.1: Jangan pernah biarkan pengguna menunggu apa pun.

Yang perlu diingat adalah halaman yang terus tumbuh yang membutuhkan 10 detik muncul jauh lebih cepat daripada menunggu 3 detik sebelum layar kosong dan dapatkan sekaligus.

Jadi, alih-alih membuat halaman cepat, biarkan saja halaman tampak cepat, bahkan jika hasil akhirnya lebih lambat:

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

Kode di atas membiarkan daftar untuk bertambah baris demi baris, dan selalu lebih lambat dari render sekaligus. Tetapi bagi pengguna tampaknya lebih cepat.

Steffomio
sumber
bagaimana cara menggunakan fungsi ini di halaman html?
Antonis
9

Pengguliran virtual adalah cara lain untuk meningkatkan kinerja pengguliran ketika berhadapan dengan daftar besar dan dataset besar.

Salah satu cara untuk mengimplementasikan ini adalah dengan menggunakan Bahan Angular md-virtual-repeat seperti yang ditunjukkan pada Demo ini dengan 50.000 item

Diambil langsung dari dokumentasi virtual repeat:

Virtual repeat adalah pengganti terbatas untuk ng-repeat yang membuat node dom cukup untuk mengisi wadah dan mendaur ulang mereka sebagai gulungan pengguna.

Sarantis Tofas
sumber
2
Wow, saya pikir ini adalah jawaban yang paling menarik. Apakah ini akan bekerja dengan versi sudut yang lebih lama? (mis. ver 1.2)
Thariq Nugrohotomo
2
@ThariqNugrohotomo Harap dicatat bahwa menggunakan Bahan Angular membutuhkan penggunaan Angular 1.3.x atau lebih tinggi. Terima kasih atas dukungannya, saya juga sangat kagum dengan pengulangan virtual dan kami sudah menggunakannya pada aplikasi seluler yang menampilkan daftar hasil yang sangat panjang.
Sarantis Tofas
6

Versi lain @Steffomio

Alih-alih menambahkan setiap item secara terpisah, kami dapat menambahkan item dengan potongan.

// 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);
    }       
});
Luevano
sumber
Ide yang menarik. Saya mencoba ini pada array ~ 8000 elemen, dan sementara itu memang membuat halaman lebih responsif pada awalnya, itu menjadi kurang responsif setelah setiap potongan.
Paul Brannan
Ini adalah masalah besar pada aplikasi saya setelah memiliki lebih dari 500 item. Saya menyarankan pagination atau pemuatan tanpa batas sebagai gantinya.
joalcego
0

Kadang-kadang apa yang terjadi, Anda mendapatkan data dari server (atau back-end) dalam beberapa ms (misalnya saya saya asumsikan 100 ms ) tetapi butuh lebih banyak waktu untuk ditampilkan di halaman web kami (katakanlah dibutuhkan 900 ms untuk tampilan).

Jadi, Apa yang terjadi di sini adalah 800 ms. Dibutuhkan hanya untuk membuat halaman web.

Apa yang saya lakukan dalam aplikasi web saya adalah, saya telah menggunakan pagination (atau Anda dapat menggunakan scrolling tak terbatas juga) untuk menampilkan daftar data. Katakanlah saya menunjukkan 50 data / halaman.

Jadi saya tidak akan memuat render semua data sekaligus, hanya 50 data yang saya muat awalnya yang hanya membutuhkan 50 ms (saya asumsikan di sini).

jadi total waktu di sini berkurang dari 900 ms menjadi 150 ms, setelah pengguna meminta halaman berikutnya lalu menampilkan 50 data berikutnya dan seterusnya.

Semoga ini akan membantu Anda untuk meningkatkan kinerja. Semua yang terbaik

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

yang memuat data saat mencapai ke bawah halaman dan menghapus setengah dari data yang dimuat sebelumnya dan ketika mencapai ke atas div lagi data sebelumnya (tergantung pada nomor halaman) akan dimuat menghapus setengah dari data saat ini Jadi pada DOM pada suatu waktu hanya ada data terbatas yang dapat mengarah pada kinerja yang lebih baik daripada merender seluruh data pada beban.

KODE HTML:

<!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="[email protected]" 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>

KODE Sudut:

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 dengan arahan

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

Tergantung pada ketinggian divisi itu memuat data dan pada gulir data baru akan ditambahkan dan data sebelumnya akan dihapus.

Kode HTML:

<!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="[email protected]" 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>

Kode Sudut:

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 dengan kisi UI dengan Demo gulir tanpa batas

ankesh jain
sumber
Tautan ke suatu solusi disambut baik, tetapi harap pastikan jawaban Anda bermanfaat tanpanya: tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda akan mengetahui apa itu dan mengapa ada, lalu kutip bagian yang paling relevan dari halaman yang Anda tuju. menautkan kembali jika seandainya halaman target tidak tersedia. Jawaban yang sedikit lebih dari sebuah tautan dapat dihapus .
Sᴀᴍ Onᴇᴌᴀ
-2

untuk kumpulan data besar dan beberapa nilai drop-down lebih baik digunakan ng-optionsdaripada ng-repeat.

ng-repeatlambat karena loop semua nilai yang datang tetapi ng-optionshanya menampilkan ke opsi pilih.

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

jauh lebih cepat daripada

<option ng-repeat="state in States" value="{{state.StateCode}}">
    {{state.StateName }}
</option>
Ghebrehiywet
sumber
Apakah Anda memeriksa kinerja opsi-ng? Saya mencoba mengoptimalkan kode saya dan itu tidak membantu. Kecepatannya sama dengan ng-repeat. -1
Icet
hanya berfungsi untuk pilih, ng-repeat jauh lebih kuat. Meskipun demikian memang benar bahwa ng-Options jauh lebih cepat daripada ng-repeat. Dokumen AngularJs menyebutkan 2000 item untuk perbedaan: docs.angularjs.org/api/ng/directive/select
kaiser