Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way I can speed up the way my grid reacts when I have many rows?

Tags:

angularjs

I have code that creates a grid like this:

<div ng-repeat="row in home.grid.data track by row.examId">
   <div>{{ row.examId }}</div>
   <div>xxxx</div>
</div>

I have more columns after these.

Is there a way I can speed up the way my page reacts? It seems that when I have a lot of data in the grid then the pages reacts slowly. Would it make a difference if I used ng-model in an input type field for the row.examId. Note that some of the fields that follow can be edited but most are just display only.

like image 687
Samantha J T Star Avatar asked Sep 09 '14 10:09

Samantha J T Star


2 Answers

I believe bindonce does exactly what you need.

By reducing the number of watchers it allows the page to become more responsive. Check their demos.

like image 174
bmleite Avatar answered Oct 06 '22 02:10

bmleite


This is what I have done. There are two ways. Irrespective of both solutions, use bindOnce. Keep a look out on the number of watchers on the page. Look at the end of this solution - how to keep track of watchers on a page.

I have added a solution 3 and this is working awesome, styling is a bit difficult

Solution 1:

Use a pagination control with bind once.

Solution 2 This is what worked for me and it is very elegant. You repeat with bindonce and then implement infinite scrolling. I have followed this blog post and it works like a charm. The idea is you limit the number of rows and change the limit as you scroll.

ng-repeat="item in items | orderBy:prop | filter:query | limitTo:limit"

Essentially, your html would look like this. I have modified the OP's code to use bindonce.

 <div id="estates-listing"  extend-height>
  <div class="content" infinite-scroll="addMoreItems()" infinite-scroll-distance="2">
    <div class="content-wrapper">
      <div class="house" bindonce="estate" ng-animate="'animate'" ng-class="{inactive: (selectedEstate != null || selectedEstate != undefined) && estate.id!=selectedEstate.id , active:(selectedEstate != null || selectedEstate != undefined) && estate.id==selectedEstate.id}" ng-repeat="estate in estates | orderBy: orderProp : orderReverse | limitTo: config.itemsDisplayedInList track by estate.id" ng-mouseover="highlightMarker(estate)" ng-mouseleave="leaveMarker(estate)" ng-click="showDetailview(estate.id)" >
        <div id="l-el{{estate.id}}">
        </div>
      </div>
    </div>
  </div>
</div>

Here is the infinite scroll directive from the post. Add this to your app, please don't use the standard infinite scroll using bower install.

app.directive('infiniteScroll', [
  '$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) {
    return {
      link: function(scope, elem, attrs) {
        var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
        $window = angular.element($window);
        elem.css('overflow-y', 'scroll');
        elem.css('overflow-x', 'hidden');
        elem.css('height', 'inherit');
        scrollDistance = 0;
        if (attrs.infiniteScrollDistance != null) {
          scope.$watch(attrs.infiniteScrollDistance, function(value) {
            return scrollDistance = parseInt(value, 10);
          });
        }
        scrollEnabled = true;
        checkWhenEnabled = false;
        if (attrs.infiniteScrollDisabled != null) {
          scope.$watch(attrs.infiniteScrollDisabled, function(value) {
            scrollEnabled = !value;
            if (scrollEnabled && checkWhenEnabled) {
              checkWhenEnabled = false;
              return handler();
            }
          });
        }
        $rootScope.$on('refreshStart', function(event, parameters){
            elem.animate({ scrollTop: "0" });
        });
        handler = function() {
          var container, elementBottom, remaining, shouldScroll, containerBottom;
          container = $(elem.children()[0]);
          elementBottom = elem.offset().top + elem.height();
          containerBottom = container.offset().top + container.height();
          remaining = containerBottom - elementBottom ;
          shouldScroll = remaining <= elem.height() * scrollDistance;
          if (shouldScroll && scrollEnabled) {
            if ($rootScope.$$phase) {
              return scope.$eval(attrs.infiniteScroll);
            } else {
              return scope.$apply(attrs.infiniteScroll);
            }
          } else if (shouldScroll) {
            return checkWhenEnabled = true;
          }
        };
        elem.on('scroll', handler);
        scope.$on('$destroy', function() {
          return $window.off('scroll', handler);
        });
        return $timeout((function() {
          if (attrs.infiniteScrollImmediateCheck) {
            if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
              return handler();
            }
          } else {
            return handler();
          }
        }), 0);
      }
    };
  }
]);

Solution 3: Be adventurous and use UI-Grid, UI Grid is the new ng-grid. It is not production ready, but we are playing around in production in a table where we have over 1000 records- out of the box it is awesome. The tutorials are extensive but not much SO support. It has virtualization in built and since it is an extension of ng-grid, it has a lot of backward compatibility. Here is a example with 10,000 rows

Number of watchers on the page: Here is a function to track the number of watchers on the page. The thumb rule is never exceed 2500 watchers, but we restrict ourselves to < 1000.

 $scope.TotalWatchers = function () {
                var root = $(document.getElementsByTagName('body'));
                var watchers = 0;

                var f = function (element) {
                    if (element.data().hasOwnProperty('$scope')) {
                        watchers += (element.data().$scope.$$watchers || []).length;
                    }

                    angular.forEach(element.children(), function (childElement) {
                        f(angular.element(childElement));
                    });
                };

                f(root);

                return watchers;
            };
like image 20
Pradeep Mahdevu Avatar answered Oct 06 '22 01:10

Pradeep Mahdevu