Shamoon
Shamoon

Reputation: 43491

Loading a lot of elements for ng-repeat

I have a page that needs to load thousands of rows from an API (via an AngularJS service). Rather than do it all at once, I decided to load in 100 at a time, ala:

$scope.fetchTransactions = function(page) {
  TransactionService.get($scope.product, page).then(function(response) {
    $scope.transactions = $scope.transactions.concat(response.data.transactions);

    if(response.data.transactions.length > 0) {
      $timeout(function() {
        $scope.fetchTransactions(page + 1);
      }, 1000);
    }
  });
}
$scope.fetchTransactions(1);

This loads 100 transactions at a time. In my view, I have a table and a tr that looks like:

<tr class="fade-in-repeat" ng-repeat="transaction in transactions | orderBy: ['-txid', '-time']>

When it loads, the browser freezes for a second here and there. What can I do to speed that up?

** SAMPLE JSON for one transaction **

{
  "__v":1,
  "_id":"52e7c99dc22c6f16aee227e7",
  "blockhash":"00000000186a147b91a88d37360cf3a525ec5f61c1101cc42da3b67fcdd5b5f8",
  "blockheight":51741,
  "blockorder":601,
  "blocktime":1271619803,
  "locktime":0,
  "time":1271619803,
  "txid":"0a37858c0d00af40cce12256133d7e743c42ffb345e8826d3e6700c6d0745413",
  "version":1,
  "vin_total":27.34,
  "vout_total":27.34,
  "updatedOn":"2014-01-28T15:15:41.508Z",
  "indexedOn":"2014-01-28T15:15:41.508Z",
  "vout_addresses":[
    "1CQXTdQYwquztA6jry2NjDVfRoizPco5rR",
    "1XPTgDRhN8RFnzniWCddobD9iKZatrvH4"
  ],
  "vout":[
    {
      "n":0,
      "spent_txid":"60417dc3a354910719c32eb3e70f14f971807cbb3a3c6b0b1cccc7b09c838115",
      "value":27.33,
      "scriptPubKey":{
        "reqSigs":1,
        "type":"pubkeyhash",
        "addresses":[
          "1CQXTdQYwquztA6jry2NjDVfRoizPco5rR"
        ]
      }
    },
    {
      "n":1,
      "spent_txid":"77036fa2ac75212be1ce93e8e1008d5cb2bcbb51aa560a5fe29c9c1423bbd00e",
      "value":0.01,
      "scriptPubKey":{
        "reqSigs":1,
        "type":"pubkeyhash",
        "addresses":[
          "1XPTgDRhN8RFnzniWCddobD9iKZatrvH4"
        ]
      }
    }
  ],
  "vin":[
    {
      "_id":"52e7c99dc22c6f16aee227e8",
      "sequence":4294967295,
      "txid":"c0eea97dc593f059f90630839557a5df1c3c8d7b73e01e5c8c01b89764705583",
      "vout":1,
      "meta":{
        "address":"13QaytjPv9cAJbDjGZCKCthxd8kHtSWKHE",
        "amount":27.34
      }
    }
  ]
}

Upvotes: 2

Views: 475

Answers (2)

Alex Choroshin
Alex Choroshin

Reputation: 6187

In angular when you work with thousands of rows using ng-repeat is a bad idea since it adds $watch to each element and as a result has a direct impact on performance.

so for now the best thing you could do is to work with the DOM your self, I would suggest creating your own directive and iterate the elements using the native JavaScript API or JQuery, it doesn't matter, also i would suggest using CreateDocumentFragment for DOM manipulations (why would you want to use CreateDocumentFragment).

Example:

  mainApp.directive("myRepeater", function () {
   var LIST_ITEM = "li";
        return {            
            restrict: "A",
            link: function (scope, element, attrs) {
                var rawElm = element[0];        
                scope.$watch(attrs.source, function(newValue) {
                    if (!newValue || !newValue.length || newValue.length === 0) return;

                    // wipe the previous list
                    rawElm.innerHTML = "";
                    var frag = document.createDocumentFragment();

                    newValue.forEach(function (item) {
                        var listItemNd = document.createElement(LIST_ITEM);
                        var textNd = document.createTextNode("your text");
                        listItemNd.appendChild(textNd);
                        frag.appendChild(listItemNd);
                    });

                    rawElm.appendChild(frag);
                });
            }
        };
    });

Upvotes: 2

Ilan Frumer
Ilan Frumer

Reputation: 32357

Try to pre-filter it like so (inject $filter):

$scope.fetchTransactions = function(page) {
  TransactionService.get($scope.product, page).then(function(response) {

    if(response.data.transactions.length > 0) {

      var transactions = $scope.transactions.concat(response.data.transactions);
      $scope.transactions = $filter('orderBy')(transactions, ['-txid', '-time']);

      $timeout(function() {
        $scope.fetchTransactions(page + 1);
      }, 1000);
    }
  });
}

And also use track by:

<tr class="fade-in-repeat" 
    ng-repeat="transaction in transactions track by transaction ._id">

Upvotes: 0

Related Questions