Infinite Scroll With Angular

Today let’s see how to create a simple infinite scroll using directives with angular.

The algorithm for an infinite scroll is pretty simple, you just have to check everytime your user use the scroll if the bottom of your element it close to the bottom of the visible area of the user (the bottom of the page because everything after will not be visible so nothing should appear after even footer ;) ).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
angular.module('infiniteScroll', [])
.directive 'infiniteScroll', ($window, $q) ->
  {
    link: (scope, element, attrs) ->
      offset = parseInt(attrs.offset, 10) || 10
      scrolling = false
      angular.element($window).bind 'scroll', ->
        if not scrolling and element[0].offsetParent?.offsetTop + parseInt(element[0].style.height, 10) < $window.scrollY + $window.innerHeight - offset
          scrolling = true
          deferred = $q.defer()
          scope[attrs.infiniteScroll](deferred)
          deferred.promise.then ->
            scrolling = false
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
angular.module('infiniteScroll', []).directive('infiniteScroll', function($window, $q) {
  return {
    link: function(scope, element, attrs) {
      var offset, scrolling;
      offset = parseInt(attrs.offset, 10) || 10;
      scrolling = false;
      return angular.element($window).bind('scroll', function() {
        var deferred, _ref;
        if (!scrolling && ((_ref = element[0].offsetParent) != null ? _ref.offsetTop : void 0) + parseInt(element[0].style.height, 10) < $window.scrollY + $window.innerHeight - offset) {
          scrolling = true;
          deferred = $q.defer();
          scope[attrs.infiniteScroll](deferred);
          return deferred.promise.then(function() {
            return scrolling = false;
          });
        }
      });
    }
  };
});
Toggle coffeescript/javascript

Ok now I explain some choices in this code.

  • I used a boolean to know if it’s scrolling or not to avoid multiple calls when you load something for example
  • The condition check if it’s not scrolling and if the bottom of the element is less than the bottom of the page minus an offset
  • I use a deferred object to be able to have an asynchronous call (ajax for example) and just have to resolve the deferred object when everything is complete, no need any callback

Right, this was the biggest part, now to use it you simply have to add the infinite-scroll attribute with the function to call and everytime you will arrive at the end of the page this function will be call and you will just have to resolve your deferred object when everything is done

1
2
3
4
5
6
angular.module('app', ['infiniteScroll'])
.controller 'myCtrl', ($scope) ->
  $scope.data = []
  $scope.loadNew = (deferredObj) ->
    # add some data in your data array
    deferredObj.resolve()
1
2
3
4
5
6
angular.module('app', ['infiniteScroll']).controller('myCtrl', function($scope) {
  $scope.data = [];
  return $scope.loadNew = function(deferredObj) {
    return deferredObj.resolve();
  };
});
Toggle coffeescript/javascript
1
2
3
  <div infinite-scroll="loadNew">
    <div ng-repeat="d in data"></div>
  </div>

Everything is done, in just few lines you can have an infinite scroll. In the next days, I will do an article to use pagination with angular and to link the infinite scroll with this pagination.

Comments

Copyright © 2014 - Anthony Estebe -