M. Mar
M. Mar

Reputation: 137

Scrolling upwards

I want to make a function that will automatically display items as the user scrolls upwards. Think messages, where older ones are up top, but we start at the bottom with the newest ones. I have another function that loads items at the bottom of a container, and as it does so, the current items remain in position, and scrollbar is smaller. We are not scrolled to the bottom. However, with the other direction, when I prepend items to an array, it scrolls all the way to the top, displaying the top of the loaded items, instead of remaining in the same place and letting the user scroll up as needed.

My code for the bottom scroll is this:

attachScrollWatcher: function (element, offset, callback) {

    console.log('scrolling');

    var contentHeight = element.scrollHeight;
    var yOffset = element.scrollTop;
    var y = yOffset + element.offsetHeight;

    if (y >= ( contentHeight - offset ))
    {
        callback();
    }
}

This function is attached to an object's onscroll event. However, now I need to make a function that does the opposite, going upwards. Any ideas how this can be implemented?

Upvotes: 0

Views: 263

Answers (2)

I wrestled a bear once.
I wrestled a bear once.

Reputation: 23379

Basically, when scrollTop === 0 then you're at the top and you need to load a new item..

attachScrollWatcher: function (element, offset, callback) {
    if(!element.scrollHeight) callback();
}

The problem is, loading a new item will keep the scrollTop at zero, so the user would have to scroll down and then scroll back up in order for the callback to be triggered again. So, what you wanna do is calculate the scrollHeight before the new item is added and then again after the item is added and then manually set the scrollTop to the difference between the original and the new scrollHeight.

Check out my example attachScrollListener method below...

class upScroller{

  constructor(ele = document.body){
    this.renderedItems = 0;
    this.ele = ele; var i=0;
    this.initBoxContents();
  }

  initBoxContents(){
    if(this.ele.scrollHeight == this.ele.clientHeight) 
      this.populateNextItem().then(()=>this.initBoxContents());
     else{
      this.ele.scrollTop = this.ele.clientHeight;
      this.attachScrollListener();
     }
  }

  getNextItem(){
    // Do something here to get the next item to render
    // preferably using ajax but I'm using setTimeout 
    // to emulate the ajax call.
    return new Promise(done=>setTimeout(()=>{
      this.renderedItems++;
      done(`<p>This is paragraph #${this.renderedItems}</p>`);
    },50));
  }

  populateNextItem(){
    return new Promise(done=>{
      this.getNextItem().then(item=>{
        this.ele.insertAdjacentHTML('afterbegin', item);
        done();
      });
    });
  }

  attachScrollListener(){
    this.ele.addEventListener('scroll', ()=>{
      if(this.ele.scrollTop) return;
      var sh = this.ele.scrollHeight;
      this.populateNextItem().then(()=>{
        this.ele.scrollTop = this.ele.scrollHeight - sh;
      });
    });
  }
}

var poop = document.getElementById('poop');
new upScroller(poop);
#poop{ height: 300px; overflow: auto; border:1px solid black;}
<div id=poop></div>

I've posted this here as well....

Upvotes: 1

Conor
Conor

Reputation: 21

Something like this may work.

attachScrollWatcher: function (element, offset, callback) {

console.log('scrolling');

var contentHeight = element.scrollHeight;
var yOffset = element.scrollTop;
var y = yOffset + element.offsetHeight;

if (y >= ( contentHeight - offset ))
{
    callback();
} else {
    callbackGoingUp();
}
}

Upvotes: 0

Related Questions