How to infinite-scroll with distance from top instead of bottom (good for chat scroll history)

Right now infinite scroll only supports the parameter distance as the percentage scrolled to the bottom. How do you do this for percentage scrolled to the top? This is essential for chat-style scrolls where you load more chat history as the User scrolls to the top. Anyone? hacks?

3 Likes

I ditched the infinite scroll and went with this simple solution:

  // Controller
  $scope.loadMore = function() {
    // fetch data here...
  };

  $scope.onChatScroll = ionic.debounce(function(top) {
    if ($ionicScrollDelegate.getScrollPosition().top <= top) {
      $scope.loadMore();
    }
  }, 500);

  // View
  <ion-scroll on-scroll="onChatScroll(10)">
    <ion-list>
      <ion-item ng-repeat=""></ion-item>
    </ion-list>
  </ion-scroll>

Take note on the use of ionic.debounce to trigger that callback once in 500ms.

3 Likes

@deanq: Iā€™ve started using your solution for my own chat-based app, but do you have any advice on how to keep the scroll position from sticking to the top when you load more items to the list? The problem I am having it is that the scroll position when you are near the top is between 0 and 10 (or whatever you pass in to the onChatScroll() function). When new items are added to the front of the array, the scroll position still stays at the top of the view, which means now Iā€™m looking at the top of all the new items instead of where I want to be, still at the bottom of the new itemsā€¦

does this make sense?

I know the issue youā€™re talking about. I didnā€™t explore much solutions around it. I managed that by providing less historical rows. For example, if the height of the view is good for 10 chat histories, I would only return 9 per page. So every time more history is loaded per scrolling up, the user would still be able to see the last item at the bottom. You have to ask yourself, how much history per page is appropriate here?

Another avenue I was looking atā€“but didnā€™t continue pursuingā€“was $ionicScrollDelegate.anchorScroll(). My strategy was to put an anchor to every chat row, and take note of the last anchor of the new page that is being loaded. Then after the loadMore, I could just trigger anchorScroll without animation. Thereā€™s a weird catch to using anchorScroll though, so read up on that.

Iā€™ve figured out a solution that worksā€¦ it isnā€™t pretty, but it works for now. I have a button at the top of my chat history as long as there are more messages to fetch. When the view first loads and I call $ionicScrollDelegate.scrollBottom(); I also store the content height, eg: var contentHeight = document.getElementById(ā€˜chat-contentā€™).scrollHeight;

When new data is loaded, I wait little bit ($timeout of say 100ms) and then grab the new chat-content scrollHeight. I then call $ionicScrollDelegate.scrollTo(0, newHeight - oldHeight, false);

It can be a little jumpy, but at least it works, and Iā€™m not trying to load 1000ā€™s of messages at once. As for your initial suggestion, I unfortunately cannot just load a set amount of history per page as each item is variable in height. Some items take up most of the screen on their own, sometimes you can see several messages at once.

I know other apps in the wild do this without having the scroll issue. Slack is one of them. To me it seems there must be a way to freeze the content div (turn off scrolling? something with overflow? I am not sure), add the new items to the array, turn on scrolling, and resize for the new size of the content.

Anything new about this ? I need exactly the same functionnality !

2 Likes

Iā€™m also looking for a smoother solution to this. I need to keep the scrolling position stay in the same location after adding items on top the list.
As @cquartier described, Iā€™m using same temporary solution which is not completely satisfactory but works :

if (scroller.getScrollPosition().top <= 20) { //  larger the value results in more jerky list
    lastScrollHeight = document.getElementById('full-message-list').scrollHeight;	                
       pullPreviousMessages();
       $timeout(function(){ // adding some delay to load the scroller with new items
           var currentScrollHeight = document.getElementById('full-message-list').scrollHeight;
           var lastPostion = currentScrollHeight - lastScrollHeight;
           scroller.scrollTo(0, lastPostion, false);
       }, 300);                                    
}

Also, the above function is attached to the scroller element using following code :

<ion-content id="full-message-list" delegate-handle="full-message-list" on-scroll="onMesaageScroll()" scroll-event-interval="50">
1 Like

@BeRMaNyA , did you modify the ionic lib code ? Could you please elaborate

Seems that there is still no official way to do it from top?

Wow I think this is such an important feature that Ionic should include to their core. Many people (include me) need it :frowning:

1 Like

same issue here please anyone help usā€¦!

2 Likes

This seems like a problem thats too difficult for every developer to write his own solution for. It would be really cool if the infinite scroll would account for this scenario.

Thanks for this solution! I found for me performance is better without ā€œionic.debounceā€. I assume the on-scroll event already has some debouncing built in because I only see a reasonable number of events being fired.

I everyone,

Iā€™m facing same issue and tried solutions using timeouts but itā€™'s not really stableā€¦Iā€™ll try tomorow the following option:

  • create a directive and insert to the dom just before the first item of ng-repeat with a callback function like this

  • create another directive but this time insert it after the last item of ng-repeat with a callback fuction to restaure scroll to originial position

    <div ng-if="$index===$last" ng-init="restaureScrollPosition()"
     saveScrollPosition function(){
             lastScrollHeight = document.getElementById('full-message-list').scrollHeight;
      }
    
     restaureScrollPosition function(){
                 var currentScrollHeight = document.getElementById('full-message-list').scrollHeight;
                var lastPostion = currentScrollHeight - lastScrollHeight;
                 scroller.scrollTo(0, lastPostion, false);
      }
    

    I donā€™t see how to get closer to the dom rendering the process

Also running into the same issue, tried above solutions but its not really solid ā€¦ any progressive ionic team?

Thanks
A

1 Like

+1 ion infinite scroll to the top

1 Like

You can check my solution: