Progressive Enhancement KnockoutJS Infinite Scroll
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<b>Search Results</b>
<p>Progressive enhancement with KnockoutJS Infinite Scroll</p>
<!-- The first page is rendered server side -->
<div id="list" data-bind="foreach: list">
<div data-bind="PE, text: name">Listing 0</div>
<div data-bind="PE, text: name">Listing 1</div>
<div data-bind="PE, text: name">Listing 2</div>
<div data-bind="PE, text: name">Listing 3</div>
<div data-bind="PE, text: name">Listing 4</div>
<div data-bind="PE, text: name">Listing 5</div>
<div data-bind="PE, text: name">Listing 6</div>
<div data-bind="PE, text: name">Listing 7</div>
<div data-bind="PE, text: name">Listing 8</div>
<div data-bind="PE, text: name">Listing 9</div>
<div data-bind="PE, text: name">Listing 10</div>
</div>
CSS
#list div {
background-color: #eee;
margin: 5px;
height: 100px;
}
JavaScript
//Custom binding to load the values into the view model
ko.bindingHandlers.PE = {
init: function(element, valueAccessor, allBindings) {
var bindings = allBindings();
if (typeof bindings.text === 'function') {
bindings.text($(element).text());
}
}
};
// listing model
var Listing = function (listing) {
this.name = ko.observable('');
// set initial values if provided
if (listing) {
this.name(listing.name);
}
};
var getInitialData = function(results) {
// create a list of empty listings
var children = $('#list').children(),
// create a list of listings
list = _.range(children.length)
.map(function (i) {
var elm = $(children[i]),
listing = new Listing();
// get listing values from the DOM
ko.applyBindings(listing, elm[0]);
// convert the model to JSON
listing = ko.toJS(listing);
// update the max id used so far
results.maxId += 1;
// remove all but the first element
if(elm.index() > 0)
{
elm.remove();
}
return listing;
});
return list;
}
// search results view
var ResultsView = function () {
var self = this;
self.maxId = 0;
self.list = ko.observableArray(getInitialData(self));
self.pendingRequest = ko.observable(false)
};
var results = new ResultsView();
ko.applyBindings(results);
// listen for the scroll event
$(window).scroll(function () {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
getNextItems(20);
}
});
function getNextItems(cnt) {
// ignore if currently requesting data
if...