Search code examples
angularjsangularjs-directiveangularjs-scopeangularjs-http

Custom infinite scrolling trigger many times


I am new to angular was used to work with jquery.

I set a directive which listen scrolling to trigger an http.get request when the user is almost on the bottom of the document. Everything works fine but I cannot avoid the event to be trigger a lot of time at once.

here is some code if you have some suggestion that would be great !

html :

div(class="home-flex", ng-scroll, infinite-request="addMore()", ng-disabled)
    div(class="home-article", ng-repeat="article in articles", ng-cloak)
        img(class="home-article-image", ng-src="{{ article.imageUrl }}", ng-cloak)

directive :

nemi.directive('ngScroll', function($window, $document){
    return {
        link: function(scope, element, attrs){
            $document.on('scroll', function(element){
                var height = Math.max(
                    document.body.scrollHeight, document.documentElement.scrollHeight,
                    document.body.offsetHeight, document.documentElement.offsetHeight,
                    document.body.clientHeight, document.documentElement.clientHeight
                );
                // console.log("window height : " + $window.innerHeight)
                // console.log("scroll from top : " + $window.pageYOffset);
                // console.log("scroll from top + window height : " + ($window.innerHeight + $window.pageYOffset))
                // console.log("doc height : " + height);
                // console.log("scroll/doc : " +  $window.pageYOffset/height);

                if ((($window.pageYOffset + $window.innerHeight)/height) > 0.6) {
                    console.log("trigger");
                    scope.$apply(attrs.infiniteRequest);
                }

            })
        }
    }
})

annnnd my controller :

nemi.controller('homeController', [ '$scope', '$http', '$window', function($scope, $http){
    $http.get('/articles').success(function(res){
        $scope.articles = res;
    }).error(function(data){
        console.log(data);
    });

    var wait = true;
    $scope.addMore = function() {
        if (wait === true) {
            wait = false;
            console.log("trigger");
            $http.get('/articles').success(function(res) {
                res.forEach(function(elem){
                    $scope.articles.push(elem);

                })
            wait = true;
            }).error(function(){
                console.log("scroll failed");
            })
        }   
    }
}]);

my miserable attempte to block the function with my "wait boolean" works but doesnt save me from the many request at once.

I tried different things with ng-disabled but nothing worked for me so far


Solution

  • You can get a help from promise returned by $http which is happening from addMore & then do check that does request already in process or not. If no then make a call again. This way code will ensure unless one call gets completed, other will not happen.

    Controller

    nemi.controller('homeController', ['$scope', '$http', '$window', function($scope, $http, $window) {
      $http.get('/articles').success(function(res) {
        $scope.articles = res;
      }).error(function(data) {
        console.log(data);
      });
    
      var addMorePromise = null;
      $scope.addMore = function() {
        console.log("trigger");
        if (!addMorePromise) { //if no request is in progress then do it again
          addMorePromise = $http.get('/articles').then(function(response) {
            var data = response.data;
            data.forEach(function(elem) {
              $scope.articles.push(elem);
            });
          }).finally(function() {
            addMorePromise = null; //after request complete, make promise object to null
          });
        }
      }
    }]);