I am trying to do a reverse infinite scroll. I have a comment list where I receive the last 10 most recent comments and want the user to be able to scroll up to retrieve the next 10 - similar to FB where it shows the most recent comments with a 'get previous' link, but via scroll event rather than a link.
I started with http://jsfiddle.net/vojtajina/U7Bz9/ and tried to modify it to a reverse infinite scroll and pretty quickly ended up with something like this:
function Main($scope, $timeout) {
$scope.items = [];
var counter = 0;
$scope.loadMore = function() {
// simulate an ajax request
$timeout( function() {
for (var i = 0; i < 5; i++) {
$scope.items.unshift({id: counter});
counter += 10;
}}, 1000);
};
$scope.loadMore();
}
angular.module('scroll', []).directive('whenScrolled', ['$timeout', function($timeout) {
return function(scope, elm, attr) {
var raw = elm[0];
$timeout(function() {
raw.scrollTop = raw.scrollHeight;
}, 1100);
elm.bind('scroll', function() {
// note: if test for < 100 get into infinite loop due to
// the delayed render
if (raw.scrollTop === 0) {
var sh = raw.scrollHeight
scope.$apply(attr.whenScrolled);
// the items are not loaded and rendered yet, so
// this math doesn't work
raw.scrollTop = raw.scrollHeight - sh;
}
});
};
}]);
http://jsfiddle.net/digger69/FwWqb/2/
The issue is that when the next 10 items are retrieved, they are added to the top of the list and the entire list re-renders, and the item that was at the of the list is completely scrolled out of view. In the fiddle item "40" is at the top and when you scroll (down slightly) and then up to trigger the scrolled, item "90" is at the top. I'm looking for a good strategy to keep "40" at the top of the scroll area after it has rendered.
Note: In the fiddle I was able to get it to work by saving off the top li in the scroll event and calling scrollIntoView() until I added the timeout to simulate the ajax call. With the timeout the top li is scrolled into view before the request has come back and the new elements are rendered :/
var top = elm.find("li")[0];
scope.$apply(attr.whenScrolled);
top.scrollIntoView();
You can try something like this: http://jsfiddle.net/mNFmf/4/
This will scroll to the bottom of the div:
$timeout(function() {
raw.scrollTop = raw.scrollHeight;
});
And this will keep the div from scrolling up to the first item on the list:
var sh = raw.scrollHeight
scope.$apply(attr.whenScrolled);
raw.scrollTop = raw.scrollHeight - sh;
Update
To overcome the ajax request problem, try to use promises.
http://jsfiddle.net/mNFmf/8/
The loader would look something like this:
$scope.loadMore = function() {
var deferred = $q.defer();
// do ajax request here and after getting the result call:
deferred.resolve();
return deferred.promise;
};
And on the other side:
loadMore.then(function() {
/* do whatever you want after the ajax request has been fulfilled */
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With