Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering a page with infinite scroll in AngularJS

I implemented an infinite scrolling feature on my AngularJS + Node.js app.

It is based on this JSfiddle and works the same way: http://jsfiddle.net/vojtajina/U7Bz9/ HTML:

<div id="fixed" when-scrolled="loadMore()">
  <ul>
   <li ng-repeat="i in items">{{i.id}}</li>
  </ul>  
</div>​

Javascript:

function Main($scope) {
  $scope.items = [];

  var counter = 0;
   $scope.loadMore = function() {
     for (var i = 0; i < 5; i++) {
        $scope.items.push({id: counter});
        counter += 10;
     }
   };

  $scope.loadMore();
}

angular.module('scroll', []).directive('whenScrolled', function() {
  return function(scope, elm, attr) {
    var raw = elm[0];

    elm.bind('scroll', function() {
        if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
            scope.$apply(attr.whenScrolled);
        }
    });
  };
});

My reasons for implementing the infinite scroll is in order to save my users bandwidth by not loading all 1000 results and their corresponding images unless the user wants to see all of it.

However when searching within the results using an AngularJS filter I am encountering problems, because of course not all the results are there (unless the user has scrolled to the very bottom) so the search will only return a fraction of the required results.

I then removed the infinite scrolling feature in order to have the search function work properly but this provided new issues on chrome (not on Firefox though) when I open the page the browser starts loading images from the top. If I then filter the results by searching for something starting with "z" (at the very bottom of the results) Firefox switches focus and loads the results starting with "z" first (as they are then the only ones being displayed). However chrome continues loading through the list and thus the user will only see the results of their search (for "z") once all the images in the app have been loaded.

I am looking for a way to have angular provide both the infinite scroll and a proper search filter on the results at the same time. If this is not possible then a way to make chrome load the visible images first.

I am currently trying some weird stuff with a bunch of different arrays in the scope but I haven't had any luck so far.

like image 534
Rick Kleinhans Avatar asked Oct 29 '12 10:10

Rick Kleinhans


People also ask

How infinite scroll is implemented in AngularJS?

ngInfiniteScroll is a directive that you can use to implement infinite scrolling in your AngularJS applications. Simply declare which function to call when the user gets close to the bottom of the content with the directive and the module will take care of the rest.

Is infinite scroll better than pagination?

Pagination works better on websites where users are looking for specific pieces of content. Whereas infinite scroll is better suited for websites where you want users to discover and explore the content available. Infinite scroll is also much more effective for mobile devices.

How is infinite scroll implemented?

Infinite scrolling will require two key parts. One part will be a check for the window scroll position and the height of the window to determine if a user has reached the bottom of the page. Another part will be handling the request for additional information to display.

Does infinite scroll improve performance?

Above all else, infinite scroll is designed to boost user engagement and keep viewers on the page for as long as possible. If visitors have no particular goal in mind, infinite scrolling will continue to roll out relevant content in a way that is efficient, digestible, and interruption-free.


2 Answers

Since several people here had a similar issue and I was struggling myself, I took the time to create a fiddle that works (for my case).

https://jsfiddle.net/lisapfisterer/Lu4sbxps/

The main idea is to dynamically extend the limitTo value using infinite-scroll's function call

<div infinite-scroll="loadMore()" infinite-scroll-distance="20">
    <tr data-ng-repeat="logEvent in logEventFilter = (logEvents | filter:searchTerm | limitTo:numberToDisplay) track by $index">
        <td> {{$index}} </td>
        <td> {{logEvent.name}} </td>
        <td> {{numberToDisplay}} </td>
    </tr>
</div>

loadMore just increases the limit

$scope.loadMore = function() {
    if ($scope.numberToDisplay + 5 < $scope.logEvents.length) {
        $scope.numberToDisplay += 5;
    } else {
        $scope.numberToDisplay = $scope.logEvents.length;
    }
};
like image 91
lisa p. Avatar answered Oct 24 '22 20:10

lisa p.


What you want to do isn't "impossible" but it's certainly going to be a little complicated.

  • Have your server do all of the "filtering" to ensure that the paginated values returned are the proper values for the filter(s).
  • When the server returns the results, render all of the HTML to the screen except the src attributes of image tags. This way none of the images will begin loading yet.
  • Scroll to the proper "page".
  • Make sure all of the heights prior to the images being loaded are the same, now do some JS magic to figure out which ones are visible.
  • Set the src attribute of the visible images only, Subscribe to their "load" events and create a $q promise that is complete once all loads are complete.
  • after that promise completes, set the rest of the image src attributes so the remainder of the images will load.
like image 35
Ben Lesh Avatar answered Oct 24 '22 21:10

Ben Lesh