Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Added support for in element scrolling #17

merged 4 commits into from

3 participants


Added support for infinite scrolling for elements with overflow set to
auto. This is enabled via the options hash by setting
useElementScroll to true


Sai Wong added some commits
Sai Wong Added support for in element scrolling
Added support for infinite scrolling for elements with overflow set to
auto. This is enabled via the `options` hash by setting
`useElementScroll` to `true`
Sai Wong Fixed runtime error due to typo d20c1b8

Works, but I think some improvements could be made.

  1. To remove a lot of the conditional logic, instead of listView.parent existing only under certain conditions, listView.$scrollParent could exist always. If it should scroll within a containing element, $scrollParent is set to that element; otherwise it's set to $window. Then all scrolling-related references to $window could be replaced with $scrollParent, and the code would trivially work for both.
  2. Is there a way that this could happen automatically, instead of with an option flag? It seems possible to walk up the DOM tree from the ListView element and check the overflow-y property of each containing element. If they're all visible, the ListView should use $window for scrolling; if one is auto or scroll it should use that containing element. If it's hidden, god knows what you do -- seems silly to use Infinity at all in that case, but I guess just use the containing element to save CPU cycles. inherit would be a slightly more annoying case, but you just check the parent's overflow-y and use that for the current element.



I think the $scrollParent suggestion is good and I can add that in.

For auto-detecting what to use, I think that only opens it up for issues with fringe cases that we can probably never fully enumerate. It makes sense to for the integration code to explicitly specify it so that there is no assumptions made. Less magic = better!


Fair enough. I may still give auto-detection a shot in the future, but a configuration option that forces it to be one way or another is still a useful thing even in a world where auto-detection works. Add in the $scrollParent and I'll merge it in!


Added $scrollParent to commit!


Excellent! Merging in.

@reissbaker reissbaker merged commit adac94a into airbnb:master

Should the boundViews.push(listView) call be moved into this conditional?

I don't see harm in doing so, but this is really an internal implementation and a listView should not be attached twice.


I think this is a typo, this should be a call to .off('scroll') instead of .on('scroll')


You are right. You should submit a fix for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 4, 2012
  1. Added support for in element scrolling

    Sai Wong authored
    Added support for infinite scrolling for elements with overflow set to
    auto. This is enabled via the `options` hash by setting
    `useElementScroll` to `true`
  2. Fixed runtime error due to typo

    Sai Wong authored
Commits on Oct 11, 2012
  1. Fixed `ListView` detach logic error

    Sai Wong authored
This page is out of date. Refresh to see the latest.
Showing with 19 additions and 5 deletions.
  1. +19 −5 infinity.js
24 infinity.js
@@ -80,6 +80,8 @@
this.lazy = !!options.lazy;
this.lazyFn = options.lazy || null;
+ this.useElementScroll = options.useElementScroll === true;
initBuffer(this); = this.$el.offset().top;
@@ -89,6 +91,8 @@
this.pages = [];
this.startIndex = 0;
+ this.$scrollParent = this.useElementScroll ? $el : $window;
@@ -226,8 +230,9 @@
function updateStartIndex(listView) {
var index, length, pages, lastIndex, nextLastIndex,
startIndex = listView.startIndex,
- viewTop = $window.scrollTop() -,
- viewHeight = $window.height(),
+ viewRef = listView.$scrollParent,
+ viewTop = viewRef.scrollTop() -,
+ viewHeight = viewRef.height(),
viewBottom = viewTop + viewHeight,
nextIndex = startIndexWithinRange(listView, viewTop, viewBottom);
@@ -558,8 +563,12 @@
// event.
attach: function(listView) {
+ if(!listView.eventIsBound) {
+ listView.$scrollParent.on('scroll', scrollHandler);
+ listView.eventIsBound = true;
+ }
if(!eventIsBound) {
- $window.on('scroll', scrollHandler);
$window.on('resize', resizeHandler);
eventIsBound = true;
@@ -582,11 +591,15 @@
detach: function(listView) {
var index, length;
+ if(listView.eventIsBound) {
+ listView.$scrollParent.on('scroll', scrollHandler);
+ listView.eventIsBound = false;
+ }
for(index = 0, length = boundViews.length; index < length; index++) {
if(boundViews[index] === listView) {
boundViews.splice(index, 1);
if(boundViews.length === 0) {
- $'scroll', scrollHandler);
$'resize', resizeHandler);
eventIsBound = false;
@@ -680,7 +693,8 @@
// Returns false if the Page is at max capacity; false otherwise.
Page.prototype.hasVacancy = function() {
- return this.height < $window.height() * config.PAGE_TO_SCREEN_RATIO;
+ var viewRef = this.parent.$scrollParent;
+ return this.height < viewRef.height() * config.PAGE_TO_SCREEN_RATIO;
Something went wrong with that request. Please try again.