Làm cách nào để cải thiện hiệu suất của ngRepeat qua bộ dữ liệu khổng lồ (angular.js)?


165

Tôi có một bộ dữ liệu khổng lồ gồm vài nghìn hàng với khoảng 10 trường mỗi hàng, khoảng 2 MB dữ liệu. Tôi cần hiển thị nó trong trình duyệt. Hầu hết cách tiếp cận đơn giản (tìm nạp dữ liệu, đưa dữ liệu vào $scope, ng-repeat=""thực hiện công việc của nó) hoạt động tốt, nhưng nó đóng băng trình duyệt trong khoảng nửa phút khi bắt đầu chèn các nút vào DOM. Làm thế nào tôi nên tiếp cận vấn đề này?

Một tùy chọn là nối các hàng $scopetăng dần và đợi ngRepeathoàn tất việc chèn một đoạn vào DOM trước khi chuyển sang hàng tiếp theo. Nhưng AFAIK ngRepeat không báo cáo lại khi kết thúc "lặp lại", vì vậy nó sẽ trở nên xấu xí.

Tùy chọn khác là chia dữ liệu trên máy chủ thành các trang và tìm nạp chúng trong nhiều yêu cầu, nhưng điều đó thậm chí còn xấu hơn.

Tôi đã xem qua tài liệu Angular để tìm kiếm một cái gì đó như ng-repeat="data in dataset" ng-repeat-steps="500", nhưng không tìm thấy gì. Tôi khá mới mẻ với các cách Angular, vì vậy có thể là tôi hoàn toàn thiếu điểm. Các thực hành tốt nhất tại đây là gì?


10
Bạn có thực sự muốn hiển thị TẤT CẢ các hàng? Điều gì về việc chỉ hiển thị nhiều hàng mà người dùng có thể nhìn thấy. ví dụ: bạn chỉ có thể sử dụng limitTođể hiển thị 20 mục: <p ng-repeat="data in dataset | limitTo:20">{{data}}</p>Điều này chỉ hiển thị 20 mục. Sau đó, bạn có thể sử dụng các trang và hiển thị 10 mục tiếp theo hoặc đại loại như thế. :)
AndreM96

cho điều đó "báo cáo lại khi kết thúc 'lặp lại" "điều bạn có thể sử dụng một lệnh tùy chỉnh ngoài ng-repeat. (xem tại đây câu trả lời được chọn) stackoverflow.com/questions/13471129/ từ
mayankcpdixit

tham khảo câu hỏi này nó chắc chắn sẽ giúp bạn. [nhập mô tả liên kết tại đây] [1] [1]: stackoverflow.com/questions/25481021/iêu
Mahesh

Câu trả lời:


159

Tôi đồng ý với @ AndreM96 rằng cách tiếp cận tốt nhất là chỉ hiển thị một số lượng hàng hạn chế, UX nhanh hơn và tốt hơn, điều này có thể được thực hiện bằng cách phân trang hoặc với một cuộn vô hạn.

Cuộn vô hạn với góc là thực sự đơn giản với limitTo lọc. Bạn chỉ cần đặt giới hạn ban đầu và khi người dùng yêu cầu thêm dữ liệu (tôi đang sử dụng một nút để đơn giản), bạn sẽ tăng giới hạn.

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

Đây là một JsBin .

Cách tiếp cận này có thể là một vấn đề đối với điện thoại vì thông thường chúng bị lag khi cuộn nhiều dữ liệu, vì vậy trong trường hợp này tôi nghĩ rằng một phân trang phù hợp hơn.

Để làm điều đó, bạn sẽ cần bộ lọc giới hạn và cũng là bộ lọc tùy chỉnh để xác định điểm bắt đầu của dữ liệu được hiển thị.

Đây là một JSBin với một phân trang.


Đẹp thay thế !!! Bạn biết bất kỳ phương pháp nào để sử dụng nếu tôi bị ràng buộc hiển thị tất cả các mục. bất kỳ dấu hiệu tải hoặc một sau khi chèn vào DOM hoặc một cái gì đó?
mayankcpdixit

Bạn có nghĩa là hiển thị một "tải ..." hoặc một cái gì đó trong khi dữ liệu đang được tìm nạp?
Bertrand

1
@Sumit giới hạn sẽ được áp dụng cho phạm vi lặp lại, do đó, kết quả sẽ là một mảng mới sẽ được chuyển sang ng-repeat, mảng dữ liệu của bạn vẫn như cũ và bạn vẫn có thể tìm kiếm tất cả nội dung.
Bertrand

12
Nếu người dùng nhấn loadmore 10 lần và mỗi lần nhấn thêm 100 mục, làm thế nào để cải thiện hiệu suất?
hariszaman

5
@hariszaman Tôi đồng ý. Điều này không cải thiện hiệu suất. Nó chỉ trì hoãn hiệu suất kém. Cuộn vô hạn sẽ khiến bạn gặp rắc rối trừ khi bạn đang ảo hóa nó (điều mà ui-lưới làm).
Richard

41

Cách tiếp cận nóng nhất - và có thể mở rộng nhất - để vượt qua những thách thức này với các bộ dữ liệu lớn được thể hiện bằng cách tiếp cận chỉ thị của bộ sưu tập Ionic và các triển khai khác giống như nó. Một thuật ngữ ưa thích cho điều này là 'loại bỏ tắc nghẽn' , nhưng thay vào đó, bạn có thể tóm tắt nó là: không chỉ giới hạn số lượng phần tử DOM được kết xuất thành một số phân trang tùy ý (nhưng vẫn cao) như 50, 100, 500 ... , chỉ giới hạn ở nhiều yếu tố mà người dùng có thể thấy .

Nếu bạn làm một cái gì đó giống như cái thường được gọi là "cuộn vô hạn", bạn sẽ giảm phần nào số lượng DOM ban đầu , nhưng nó sẽ nở nhanh sau khi một vài lần làm mới, bởi vì tất cả các yếu tố mới này chỉ được xử lý ở phía dưới. Cuộn đến để thu thập thông tin, bởi vì cuộn là tất cả về số lượng phần tử. Không có gì vô hạn về nó.

Trong khi đó, collectionRepeatcách tiếp cận là chỉ sử dụng càng nhiều phần tử sẽ phù hợp với chế độ xem, sau đó tái chế chúng . Khi một phần tử xoay ra khỏi tầm nhìn, nó tách ra khỏi cây kết xuất, được nạp lại dữ liệu cho một mục mới trong danh sách, sau đó được gắn lại vào cây kết xuất ở đầu kia của danh sách. Đây là cách nhanh nhất mà con người biết để có được thông tin mới trong và ngoài DOM, sử dụng một tập hợp các yếu tố hiện có hạn chế, thay vì chu trình tạo / hủy ... truyền thống tạo / hủy. Sử dụng phương pháp này, bạn thực sự có thể thực hiện một cuộn vô hạn .

Lưu ý rằng bạn không phải sử dụng Ionic để sử dụng / hack / thích nghi collectionRepeathoặc bất kỳ công cụ nào khác giống như vậy. Đó là lý do tại sao họ gọi nó là nguồn mở. :-) (Điều đó nói rằng, nhóm Ionic đang làm một số điều khá khéo léo, xứng đáng với sự chú ý của bạn.)


Có ít nhất một ví dụ tuyệt vời về việc làm một cái gì đó rất giống trong React. Chỉ thay vì tái chế các yếu tố với nội dung được cập nhật, bạn chỉ cần chọn không hiển thị bất cứ thứ gì trong cây không có trong tầm nhìn. Nó rất nhanh với 5000 mặt hàng, mặc dù việc triển khai POC rất đơn giản của chúng cho phép một chút nhấp nháy ...


Ngoài ra ... để lặp lại một số bài đăng khác, sử dụng track byrất hữu ích, ngay cả với các bộ dữ liệu nhỏ hơn. Coi nó là bắt buộc


Ý tưởng tuyệt vời của nhóm Ionic. Tôi tự hỏi nếu điều đó đến từ cách hiển thị bản địa?
Lũ Bradley

Chẳng hạn, UITableView trong iOS sử dụng cùng một cách tiếp cận để hiển thị các tập dữ liệu lớn. Tôi nghĩ rằng đây là một cách tiếp cận phổ biến được sử dụng trong nhiều quan điểm bản địa.
Dmitry Kotenko

36

Tôi khuyên bạn nên xem điều này:

Tối ưu hóa AngularJS: 1200ms đến 35ms

họ đã thực hiện một chỉ thị mới bằng cách tối ưu hóa ng-repeat ở 4 phần:

Tối ưu hóa số 1: Các phần tử DOM Cache

Tối ưu hóa số 2: Người theo dõi tổng hợp

Tối ưu hóa số 3: Trì hoãn việc tạo phần tử

Tối ưu hóa số 4: Bỏ qua người theo dõi cho các yếu tố ẩn

dự án ở đây trên github:

Sử dụng:

1- bao gồm các tệp này trong ứng dụng một trang của bạn:

  • core.js
  • scalyr.js
  • slyEvaliated.js
  • slyRepeat.js

2- thêm phụ thuộc mô-đun:

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

3- thay thế ng-lặp lại

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

Thưởng thức!


4
Tôi nghĩ scalyr.js này đã bao gồm các tệp khác. Bởi vì là kết quả của kịch bản xây dựng.
dnocode

Tôi đã thử sử dụng Scalyr nhưng bộ lọc không hoạt động. Tùy chọn <tr sly-repeat = "trong main.customers | filter: search_input | limitTo: 20">
aldesabido

Điều này là vô cùng hữu ích. Tôi đang sử dụng nó trên ứng dụng AngularJS 1.6 nơi khách hàng muốn xem nhiều ô dữ liệu (thông thường tôi thiết kế biểu mẫu với các yếu tố phân trang / giảm dữ liệu nhưng khách hàng cần so sánh nhiều dữ liệu cùng một lúc). Cho đến nay, lưới các tế bào đã chuyển từ không sử dụng sang hoàn toàn tốt vì thư viện này. Nhưng lib này đã được viết cách trở lại trong AngularJS 1,2 ngày nên tôi sẽ kiểm tra cẩn thận để tìm kiếm các vấn đề.
tờ rơi

Từ những gì tôi có thể nói vào lúc này, tệp gatedScope.js (323 dòng) là tệp duy nhất cần được xác minh để có thể chạy được trên các phiên bản AngularJS hiện tại. Yêu cầu kéo này là đáng chú ý: github.com/karser/angular/commit/ ,. Nó cập nhật rootScope chữ ký. $ Mới.
tờ rơi

bao gồm tất cả bốn tệp js và được sử dụng sly-repeatnhưng không có gì giúp tôi kết quả vẫn chậm và trình duyệt bị chậm cũng bị vi phạm [Violation] 'setTimeout' handler took 54ms,[Violation] 'scroll' handler took 1298ms
Gaurav Aggarwal

15

Bên cạnh tất cả các gợi ý ở trên như theo dõi và các vòng nhỏ hơn, điều này cũng giúp tôi rất nhiều

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

đoạn mã này sẽ in tên một khi nó đã được tải và dừng xem nó sau đó. Tương tự, đối với ng-lặp lại, nó có thể được sử dụng như

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

tuy nhiên nó chỉ hoạt động cho AngularJS phiên bản 1.3 trở lên. Từ http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/


Bạn có cần sự ::lặp lại cũng như biểu thức không? Các tài liệu nói khác, nhưng tôi không chắc chắn cách nào để kiểm tra xem cái này có hoạt động không. docs.angularjs.org/guide/expression
Ramirez

12

Bạn có thể sử dụng "theo dõi" để tăng hiệu suất:

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

Nhanh hơn so với:

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

ref: https : //www.air Pair.com/angularjs/posts/angularjs-performance-large-appluggest


1
Điều này không thực sự giúp ích cho hiệu suất. Xem jsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
ilter

với theo dõi bởi bạn không theo dõi phần tử mảng ngay từ đầu mỗi khi bạn nhận được dữ liệu mới. kết quả là điều này cải thiện hiệu suất.
dùng1920302

2
Điều này chỉ hữu ích khi dữ liệu trong ng-repeat thay đổi. Đối với tải ban đầu, nó có thể không tạo ra sự cải thiện hiệu suất.
Sumesh Kuttan

11

Nếu tất cả các hàng của bạn có chiều cao bằng nhau, bạn chắc chắn nên xem qua ảo hóa ng-repeat: http://kamilkp.github.io/angular-vs-repeat/

Bản demo này có vẻ rất hứa hẹn (và nó hỗ trợ cuộn quán tính)


2
Hiệu suất cuộn trên thiết bị di động không được chấp nhận (các sự kiện cuộn không kích hoạt trên iOS dành cho thiết bị di động (chỉ tăng từ 8)
Johny

9

Quy tắc số 1: Không bao giờ để người dùng chờ đợi bất cứ điều gì.

Điều đó trong tâm trí một trang phát triển cuộc sống cần 10 giây xuất hiện nhanh hơn so với chờ 3 giây trước khi màn hình trống và nhận được tất cả cùng một lúc.

Vì vậy, thay vì làm cho trang nhanh, chỉ cần để trang có vẻ nhanh, ngay cả khi kết quả cuối cùng chậm hơn:

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

Đoạn mã trên cho phép xuất hiện danh sách đang tăng dần theo từng hàng và luôn chậm hơn kết xuất cùng một lúc. Nhưng đối với người dùng thì nó dường như nhanh hơn.


Làm thế nào để sử dụng chức năng này trong trang html?
Antonis

9

Cuộn ảo là một cách khác để cải thiện hiệu suất cuộn khi xử lý các danh sách lớn và tập dữ liệu lớn.

Một cách để thực hiện điều này là sử dụng Vật liệu góc md-virtual-repeat như được thể hiện trên bản Demo này với 50.000 mục

Lấy thẳng từ tài liệu lặp lại ảo:

Lặp lại ảo là một thay thế hạn chế cho ng-repeat chỉ hiển thị các nút dom đủ để lấp đầy container và tái chế chúng khi người dùng cuộn.


2
Wow, tôi nghĩ rằng đây là câu trả lời thú vị nhất. Điều này sẽ làm việc với phiên bản cũ hơn của góc? (ví dụ ver 1.2)
Thariq Nugrohotomo 23/8/2016

2
@ThariqNugrohotomo Xin lưu ý rằng việc sử dụng Vật liệu góc đòi hỏi phải sử dụng Angular 1.3.x trở lên. Cũng cảm ơn sự hỗ trợ, tôi thực sự ngạc nhiên vì lặp lại ảo và chúng tôi đã sử dụng nó trên một ứng dụng di động hiển thị một danh sách kết quả thực sự dài.
Sarantis Tofas

6

Phiên bản khác @Steffomio

Thay vì thêm từng mục riêng lẻ, chúng ta có thể thêm các mục theo từng phần.

// 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);
    }       
});

Ý tưởng thú vị. Tôi đã thử điều này trên một mảng ~ 8000 phần tử và trong khi nó làm cho trang phản hồi nhanh hơn ban đầu, nó trở nên ít phản hồi hơn sau mỗi đoạn.
Paul Brannan

Đây là một vấn đề lớn trên ứng dụng của tôi sau khi có hơn 500 mặt hàng. Tôi đề nghị phân trang hoặc tải vô hạn thay thế.
joalcego

0

Đôi khi điều gì đã xảy ra, bạn nhận được dữ liệu từ máy chủ (hoặc back-end) trong vài ms (ví dụ: Tôi giả sử là 100ms) nhưng phải mất nhiều thời gian hơn để hiển thị trên trang web của chúng tôi (giả sử phải mất 900ms để trưng bày).

Vì vậy, những gì đang xảy ra ở đây là 800ms Chỉ cần kết xuất trang web.

Những gì tôi đã làm trong ứng dụng web của mình là, tôi đã sử dụng phân trang (hoặc bạn cũng có thể sử dụng cuộn vô hạn ) để hiển thị danh sách dữ liệu. Giả sử tôi đang hiển thị 50 dữ liệu / trang.

Vì vậy, tôi sẽ không tải kết xuất tất cả dữ liệu cùng một lúc, chỉ 50 dữ liệu tôi đang tải ban đầu chỉ mất 50ms (tôi giả sử ở đây).

vì vậy tổng thời gian ở đây giảm từ 900ms xuống 150ms, một khi người dùng yêu cầu trang tiếp theo thì hiển thị 50 dữ liệu tiếp theo, v.v.

Hy vọng điều này sẽ giúp bạn cải thiện hiệu suất. Tất cả tốt nhất


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

tải dữ liệu khi nó xuống đến cuối trang và xóa một nửa dữ liệu đã tải trước đó và khi nó đạt đến đỉnh của div một lần nữa dữ liệu trước đó (tùy thuộc vào số trang) sẽ được tải loại bỏ một nửa dữ liệu hiện tại. tại một thời điểm chỉ có dữ liệu hạn chế có thể dẫn đến hiệu suất tốt hơn thay vì hiển thị toàn bộ dữ liệu khi tải.

MÃ 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="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>

MÃ góc:

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 với chỉ thị

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

Tùy thuộc vào chiều cao của phân chia, nó tải dữ liệu và khi cuộn dữ liệu mới sẽ được nối thêm và dữ liệu trước đó sẽ bị xóa.

Mã 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="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>

Mã góc:

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;

    }
}

Bản demo với lưới UI với bản demo cuộn vô hạn


Liên kết đến một giải pháp được hoan nghênh, nhưng vui lòng đảm bảo câu trả lời của bạn hữu ích mà không cần đến nó: thêm ngữ cảnh xung quanh liên kết để người dùng của bạn sẽ có ý tưởng về nó là gì và tại sao lại có, sau đó trích dẫn phần có liên quan nhất của trang bạn ' liên kết lại trong trường hợp trang đích không có sẵn. Câu trả lời ít hơn một liên kết có thể bị xóa .
Sᴀᴍ vào

-2

đối với tập dữ liệu lớn và nhiều giá trị thả xuống, tốt hơn là sử dụng ng-optionshơn là ng-repeat.

ng-repeatchậm vì nó lặp trên tất cả các giá trị sắp tới mà ng-optionschỉ hiển thị cho tùy chọn chọn.

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

nhanh hơn nhiều

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

Bạn đã kiểm tra hiệu suất của các tùy chọn ng? Tôi đang cố gắng tối ưu hóa mã của mình và nó không giúp được gì. Tốc độ giống như ng-lặp lại. -1
Icet

Chỉ hoạt động để chọn, ng-repeat là cách mạnh mẽ hơn. Tuy nhiên, đúng là ng-Options nhanh hơn ng-repeat. Tài liệu của AngularJs đề cập đến 2000 mục cho sự khác biệt: docs.angularjs.org/api/ng/directive/select
kaiser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.