Endless / Infinite Pagination In Dropdown

Recently I have been re-implementing the Notification Menu at OneHealth in Backbone + Marionette and wanted to incorporate endless pagination, real-time dynamic updates, and just an overall clean / simple user experience.

When building the endless pagination I had noticed when you scroll to the end of the list the body starts to scroll. Well, That’s annoying. Okay, so lets throw in a e.preventDefault() on the list scroll binding. Hmm, that doesn’t prevent the current list from scrolling. Now What?

Lets start with some simple View Setup

//Module Variables Used

this.eol (Was The End Of List Hit)

this.lastFire (Height of Last Pagination Fire)

this.collection (Backbone Collection)


  ...

 ui : {
  container : '.js-notification-list-container',
  list : '.js-notification-list',
  loadingBar : '.js-loading-bar',
  endOfList : '.js-endOfList'
 },

 /**
  * Method For Paginating through Collection
  */
 loadNext : function(){
  var self = this;
  this.ui.loadingBar.show();
  this.collection
    .nextResults(10)
    .done(function() {
      self.ui.loadingBar.hide();
    })
    .fail(function() {
      self.endOfList = true;
      self.ui.loadingBar.hide();
      self.ui.endOfList.show();
    });
  },

 onRender : function() {
   this.attachScrollWatcher();
 }

….

Here’s what I did to achieve the desired result
When attaching a scroll listener to the view;

I attached a listener for mousewheel DOMMouseScroll events on the DOM.
Then I prevent the document from scrolling when scrolling within the current list. A throttle is added so the scroll feels smoother. Then if the list is scrolled to the (bottom height- buffer) and the current list height has not attempted to paginate then the collection paginate method is fired and the lastFire is updated to the current List Height.

….

/**
 * View Event Handler Called On View Render
 */
 attachScrollWatcher : function() {
  var self = this;
  var lastFire = 0;
  //buffer so list fires before end
  var buffer = 100;

  this.ui.container.on('mousewheel DOMMouseScroll', function (e) {
    var y = $(this).scrollTop(),
     h = $(this).get(0).scrollHeight,
     ah = $(this).height();

    //-----------------
    // Scroll Prevention
    //-----------------
    var oe = e.originalEvent,
      delta = oe.wheelDelta || -oe.detail,
      scrollTo = false,
      throttle = 0.2;

    if (e.type === 'mousewheel') {
       scrollTo = delta * -1 * throttle;
    } else if (e.type === 'DOMMouseScroll') {
       scrollTo = delta;
    }

    if (scrollTo) {
      e.preventDefault();
      $(this).scrollTop(scrollTo + $(this).scrollTop());
    }
    //-----------------

   if ((y + ah) >= (h-buffer) && self.lastFire !== h && !self.eol) {
     //Store last fired Height so we won't try again
     lastFire = h;

     if (self.collection.length >= 10) {
       self.loadNext();
     } else {
       console.log("Too Few Items For Pagination");
     }
    }
  });
}
 
40
Kudos
 
40
Kudos

Now read this

Finally, It’s Happening…

I’ve been talking about the concept of a blog for quite some time but Life happens and plus writing Code trumps writing Paragraphs. ;) I started building a Blog out with Jekyll a while ago, “Transform your plain text into static websites... Continue →