Infinite Scroll

by rlivsey

HTML

<script src="https://github.com/downloads/emberjs/ember.js/ember-0.9.7.js"></script>
<script type="text/x-handlebars">
    <div class="scroll-container">
    {{view App.InfiniteScrollView contentBinding="App.items"}}
    </div>
</script>

CSS

body {
    padding: 10px;   
}

.scroll-container {
    border: 1px solid #CCC;
    height: 200px;
    width: 200px;
    overflow: auto;
    background-color: red;
    padding: 30px 0; 
}

.scroll-container ol {
}

.scroll-container li {
    padding: 5px;
    background-color: #FFF;
}

.scroll-container li:nth-of-type(odd) {
    background-color: #EEE;
}

JavaScript

App = Ember.Application.create({});

App.ItemView = Ember.View.extend({
    template: Ember.Handlebars.compile('item: {{content.text}}'),
});

App.InfiniteScrollView = Ember.CollectionView.extend({
    tagName: 'ol',
    itemViewClass: 'App.ItemView',
    scrollBuffer: 50,

    scrolledToBottom: function() {
        // store away the last item so we can scroll back to it
        this.lastView   = this.getPath("childViews.lastObject");
        this.lastOffset = this.$().parent().scrollTop();
        this.scrollDirection = "down";

        // would trigger ajax request to load in data
        this.get("content").fetchNextPage();
    },

    scrolledToTop: function() {
        // store away the top item so we can scroll back to it
        this.lastView   = this.getPath("childViews.firstObject");
        this.lastOffset = this.$().parent().scrollTop();
        this.scrollDirection = "up";

        // would trigger ajax request to load in data
        this.get("content").fetchPrevPage();
    },

    didInsertChildElements: function(view) {
        if (this.lastView) {
            var position = this.scrollDirection == "up" ? "top" : "bottom";
            this.scrollToView(this.lastView, position);
            this.lastView = null;
        } else {
            if (!this.hasSetup) {
                this.scrollToTop();
                this.hasSetup = true;
            }
        }
    },
    
    // TODO - assumes equal padding top and bottom, figure out by other dimensions
    scrollToTop: function() {
        var $container = this.$().parent();
        var padding = ($container.innerHeight() - $container.height()) / 2;
        this.$().parent().scrollTop(padding);
    },
    
    scrollToView: function(view, position) {
        if (!view) {
            return;
        }

        if (position == "top") {
            var itemTop = view.$().position().top;
            this.$().parent().scrollTop(this.lastOffset + itemTop);
        } else {
           ...