巨大なデータセット(angular.js)でngRepeatのパフォーマンスを向上させる方法は?


165

私はそれぞれ約10フィールド、約2MBのデータを持つ数千行の巨大なデータセットを持っています。ブラウザで表示する必要があります。最も単純なアプローチ(データをフェッチし$scope、それをに入れ、ng-repeat=""その仕事を任せます)は問題なく機能しますが、DOMへのノードの挿入を開始すると、ブラウザーが約30分間フリーズします。この問題にどのように取り組むべきですか?

1つのオプションは、行を$scopeインクリメンタルに追加し、ngRepeat1つのチャンクをDOMに挿入し終えるまで待ってから、次のチャンクに移動することです。ただし、AFAIK ngRepeatは、「繰り返し」が終了してもレポートを返さないため、醜くなります。

その他のオプションは、サーバー上のデータをページに分割し、それらを複数のリクエストでフェッチすることですが、さらに醜いです。

Angularのドキュメントを調べてのようなものを探しng-repeat="data in dataset" ng-repeat-steps="500"ましたが、何も見つかりませんでした。私はAngularの方法にかなり慣れていないので、ポイントを完全に逃している可能性があります。これのベストプラクティスは何ですか?


10
すべての行を表示しますか?ユーザーが見ることができるほど多くの行だけを表示するのはどうですか。たとえば、limitTo20アイテムのみを表示するために使用できます:<p ng-repeat="data in dataset | limitTo:20">{{data}}</p>これは20アイテムのみを表示します。次に、ページを使用して、次の10項目などを表示できます。:)
AndreM96 2013年

その「「繰り返し」が終了したらレポートを返す」ために、ng-repeatに加えてカスタムディレクティブを使用できます。(ここで選択した答えを参照) stackoverflow.com/questions/13471129/...
mayankcpdixit

それがきっとあなたを助けるでしょうこの質問を参照してください。[1] [1]〜[ここで、リンクの説明を入力]:stackoverflow.com/questions/25481021/...
マヘシュ

回答:


159

@ AndreM96に同意します。最善のアプローチは、限られた量の行のみを表示し、UXをより速く、より良く表示することです。これは、ページ分割または無限スクロールを使用して行うことができます。

Angularを使用した無限スクロールは、limitToフィルターを使用すると本当に簡単です。最初の制限を設定するだけで、ユーザーがさらにデータを要求した場合(簡単にするためにボタンを使用しています)、制限を増やします。

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

これがJsBinです。

このアプローチは、多くのデータをスクロールするときに通常遅れるので、電話の問題になる可能性があります。この場合、ページネーションの方が適しています。

これを行うには、limitToフィルターと、表示されるデータの開始点を定義するカスタムフィルターも必要です。

これがページネーション付きのJSBinです。


素敵な代替品!!! すべてのアイテムを表示する必要がある場合は、どのような方法を使用してもかまいません。読み込み記号、またはDOMへの挿入後の何か
mayankcpdixit 2014年

データがフェッチされている間、「loading ...」または何かを表示することを意味しますか?
Bertrand 2014年

1
@Sumit limitToはng-repeatスコープに適用されるため、結果はng-repeatに渡される新しい配列になり、データ配列は同じままで、すべてのコンテンツを検索できます。
Bertrand

12
ユーザーがloadmoreを10回押して、1回押すたびに100項目が追加されると、どのようにしてパフォーマンスを向上させることができますか?
hariszaman 2015

5
@hariszaman同意する。これはパフォーマンスを向上させません。パフォーマンスの低下を遅らせるだけです。無限スクロールは、それを仮想化しない限り(ui-gridの場合は)問題になります。
リチャード

41

大規模なデータセットでこれらの課題を克服するための最もホットな-そして間違いなく最もスケーラブルな-アプローチは、IonicのcollectionRepeatディレクティブとそのような他の実装アプローチによって具体化されます。これの凝った用語は「オクルージョンカリング」ですが、次のようにまとめることができます。レンダリングされたDOM要素の数を、50、100、500などの任意の(ただし高い)ページ番号付きの数に制限しないでください。 、ユーザーが見ることができる要素だけに制限します

一般的に「無限スクロール」として知られているようなことを行うと、最初の DOM数は多少減少しますが、新しい要素はすべて最下部に追加されているため、2回の更新後にすぐに膨張します。スクロールは要素数の問題なので、スクロールはクロールになります。それについては無限ではありません。

一方、collectionRepeatアプローチは、ビューポートに収まるだけの数の要素のみを使用し、それらリサイクルすることです。1つの要素が回転してビューから外れると、Render Treeからデタッチされ、リスト内の新しいアイテムのデータが再入力され、リストのもう一方の端にあるRender Treeに再接続されます。これは、従来の作成/破棄...作成/破棄のサ​​イクルではなく、既存の要素の限られたセットを利用して、DOMから新しい情報を取得するために人に知られている最速の方法です。このアプローチを使用すると、本当に無限スクロールを実装できます。

Ionicを使用/ハック/適応する必要はありませんcollectionRepeat。それが彼らがそれをオープンソースと呼ぶ理由です。:-)(とは言っても、Ionicチームはかなりの独創的なことをやっているので、注目に値します。)


Reactで非常によく似たことを行う優れた例が少なくとも1つあります。更新されたコンテンツで要素をリサイクルする代わりに、表示されていないツリーには何もレンダリングしないことを選択しているだけです。非常にシンプルなPOC実装により、ちらつきが少し発生しますが、5000アイテムで高速です。


また...他のいくつかの投稿をエコーするには、track byデータセットが小さい場合でも、を使用すると非常に役立ちます。必須と考えてください。


Ionicチームによる素晴らしいアイデア。それはネイティブビューがどのようにレンダリングされるのかによるのでしょうか。
Bradley Flood

たとえば、iOSのUITableViewは、同じアプローチを使用して大きなデータセットをレンダリングします。これは多くのネイティブビューで使用される一般的なアプローチだと思います。
Dmitry Kotenko 2016

36

私はこれを見ることをお勧めします:

AngularJSの最適化:1200ms〜35ms

彼らは、4つの部分でng-repeatを最適化することにより、新しいディレクティブを作成しました。

最適化#1:DOM要素をキャッシュする

最適化#2:集約ウォッチャー

最適化#3:要素作成の延期

最適化#4:非表示要素のウォッチャーをバイパスする

プロジェクトはgithubにあります:

使用法:

1-シングルページアプリにこれらのファイルを含めます。

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

2-モジュールの依存関係を追加します。

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

3- ng-repeatを置き換える

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

楽しい!


4
このscalyr.jsにはすでに他のファイルが含まれていると思います。ビルドスクリプトの結果です。
dnocode

Scalyrを使用しようとしましたが、フィルターが機能しません。<tr sly-repeat = "main.customersのオプション|フィルター:search_input | limitTo:20">
aldesabido

これは非常に役立ちます。クライアントが大量のデータセルを表示したいAngularJS 1.6アプリで使用しています(通常、ページング/縮小されたデータ要素でフォームをデザインしますが、クライアントは一度に大量のデータを比較する必要があります)。これまでのところ、このライブラリーにより、セルのグリッドは使用不可から完全に正常になりました。しかし、このlibはAngularJS 1.2の時代に書かれたので、問題がないか注意深くテストします。
フライヤー

現時点で私が知ることができることから、より最新のバージョンのAngularJSで実行可能であることを確認する必要があるのは、gatedScope.jsファイル(323行)だけです。このプルリクエストは注目に値します:github.com/karser/angular/commit/…。署名rootScope。$ newを更新します。
チラシ2017

4つすべてのjsファイルを含めて使用しましたsly-repeatが、何も役に立たなかったため、結果はまだ遅く、ブラウザの遅延も違反[Violation] 'setTimeout' handler took 54msになっています[Violation] 'scroll' handler took 1298ms
Gaurav Aggarwal

15

上記のすべてのヒントや、小さいループのほかに、これは私を大いに助けました

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

このコードは、ロードされると名前を出力し、その後は監視を停止します。同様に、ng-repeatsの場合、次のように使用できます。

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

ただし、AngularJSバージョン1.3以降でのみ機能します。http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/から


::繰り返しだけでなく、表現が必要ですか?ドキュメントはそうではないと言っていますが、これが機能していることをテストする方法がわかりません。docs.angularjs.org/guide/expression
キリスト教のラミレス

12

「トラックバイ」を使用してパフォーマンスを向上させることができます。

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

より速い:

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

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


1
これは実際にはパフォーマンスに役立ちません。参照してくださいjsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
ILTER

track byでは、新しいデータを取得するたびに最初から配列要素を追跡しません。その結果、パフォーマンスが向上します。
user1920302 2015年

2
これは、ng-repeatのデータが変更された場合にのみ役立ちます。初期ロードの場合、パフォーマンスは向上しない可能性があります。
Sumesh Kuttan 2016

11

すべての行の高さが等しい場合は、仮想化ng-repeatを必ず確認する必要があります。http//kamilkp.github.io/angular-vs-repeat/

このデモは非常に有望に見えます(慣性スクロールをサポートしています)


2
モバイルでのスクロールパフォーマンスは受け入れられません(モバイルiOSではスクロールイベントは発生しません(8からのアップのみ)
Johny

9

ルール1:ユーザーが何かを待たせないようにします。

10秒を必要とする人生を成長させるページは、空白の画面が表示される前に3秒間待ってすべてを一度に取得するよりもはるかに速く表示されます。

したがって、ページを高速にする代わりに、最終結果が遅くても、ページが高速に見えるようにします。

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

上記のコードでは、リストが行ごとに増加しているように見え、一度にすべてをレンダリングするよりも常に低速です。しかし、ユーザーにとってはより高速に見えます。


HTMLページでこの関数を使用する方法
アントニス2016年

9

仮想スクロールは、巨大なリストや大きなデータセットを処理する際のスクロールパフォーマンスを改善するもう1つの方法です。

これを実装する1つの方法は、Angular Material md-virtual-repeatを使用することです。これは、50,000個のアイテムを含むこのデモで示されています。

バーチャルリピートのドキュメントから直接引用:

バーチャルリピートは、ng-repeatの限定的な代替手段であり、コンテナーを満たすのに十分なdomノードのみをレンダリングし、ユーザーがスクロールするとそれらをリサイクルします。


2
うわー、これが一番面白い答えだと思います。これは古いバージョンのangularで動作しますか?(例ver 1.2)
Thariq Nugrohotomo

2
@ThariqNugrohotomo Angular Materialを使用するには、Angular 1.3.x以降を使用する必要があることに注意してください。また、サポートに感謝します。バーチャルリピートにも驚いています。結果のリストが非常に長いモバイルアプリで既に使用しています。
Sarantis Tofas

6

別のバージョン@Steffomio

各アイテムを個別に追加する代わりに、チャンクでアイテムを追加できます。

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

面白いアイデア。私はこれを〜8000要素の配列で試しましたが、最初はページの応答性が向上しましたが、チャンクごとに応答性が低下しました。
ポールブランナン

これは、500を超えるアイテムがあると、私のアプリで大きな問題になりました。代わりに、ページネーションまたは無限ロードをお勧めします。
joalcego

0

時々何が起こったのか、数ミリ秒でサーバー(またはバックエンド)からデータを取得します(たとえば、100 ミリ秒と想定しています)が、Webページに表示するのに時間がかかります(900ミリ秒かかっているとしましょう)表示)。

だから、ここで起こっていることは800msですWebページをレンダリングするだけです。

私のWebアプリケーションで行ったことは、データのリストを表示するためにページネーション(または無限スクロールも使用できます)を使用したことです。50データ/ページを表示しているとしましょう。

したがって、一度にすべてのデータをロードレンダリングすることはしません。最初にロードするのは50データのみで、50ミリ秒しかかかりません(ここでは仮定しています)。

したがって、ここでの合計時間は900msから150msに減少しました。ユーザーが次のページを要求すると、次の50データが表示されます。

これがパフォーマンスの向上に役立つことを願っています。ではごきげんよう


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

これは、ページの下部に達したときにデータをロードし、以前にロードされたデータの半分を削除し、divの上部に再度到達したときに以前のデータ(ページ番号に応じて)がロードされ、現在のデータの半分を削除してロードする一度に存在するデータは限られているため、ロード時にデータ全体をレンダリングするのではなく、パフォーマンスを向上させることができます。

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>

角度コード:

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

ディレクティブ付きのデモ

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

分割の高さに応じて、データが読み込まれ、スクロール時に新しいデータが追加され、以前のデータは削除されます。

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>

角度コード:

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;

    }
}

無限スクロールデモ付きのUIグリッドを使用したデモ


ソリューションへのリンクを歓迎しますが、それがなくても回答が役に立つことを確認してください。リンクの前後にコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解し、ページの最も関連性の高い部分を引用してくださいターゲットページが利用できない場合にリンクし直します。リンクに過ぎない回答は削除される場合があります
SᴀᴍOnᴇᴌᴀ

-2

大きなデータセットと複数の値のドロップダウンの場合は、を使用するng-optionsよりも使用することをお勧めしますng-repeat

ng-repeat来るすべての値をループするので遅いが、ng-options単に選択オプションに表示する。

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

よりはるかに速い

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

ng-optionsのパフォーマンスを確認しましたか?コードを最適化しようとしていますが、効果がありませんでした。速度はng-repeatと同じです。-1
Icet

選択した場合にのみ機能し、ng-repeatの方がはるかに強力です。それにもかかわらず、ng-Optionsがng-repeatよりもはるかに高速であることは事実です。AngularJsのドキュメントでは、相違点について2000項目について言及しています:docs.angularjs.org/api/ng/directive/select
kaiser
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.