KOGrid uses virtual scrolling to render content dynamically. I'm looking for something like that but more generic so it could be used for ul
lists, Bootstrap rows, whatever. I saw something called giga-scroll, but I think it's gone now. The Git is dead.
Has anyone seen a custom binding for dynamic content via virtual scrolling?
A simple solution without using a custom binding:
Fiddler Example: http://jsfiddle.net/adrienne/Y2WUN/
Markup:
<div> <span data-bind="text: items().length"></span> <img src="http://rniemeyer.github.com/KnockMeOut/Images/loading.gif" data-bind="visible: pendingRequest" /> </div> <div id="main" data-bind="foreach: items, event: { scroll: scrolled }"> <div data-bind="text: name"></div> </div>
ViewModel:
var viewModel = { items: ko.observableArray([]), scrolled: function(data, event) { var elem = event.target; if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 200)) { getItems(20); } }, maxId: 0, pendingRequest: ko.observable(false) }; function getItems(cnt) { if (!viewModel.pendingRequest()) { //create fake data to pass to echo service var entries = []; for (var i = 0; i < cnt; i++) { var id = viewModel.maxId++; entries.push({ id: id, name: "Name" + id }); } viewModel.pendingRequest(true); $.ajax({ type: 'POST', url: '/echo/json/', data: { json: ko.toJSON(entries), delay: .1 }, success: function(entries) { ko.utils.arrayForEach(entries, function(entry) { viewModel.items.push(entry); }); viewModel.pendingRequest(false); }, error: function() { viewModel.pendingRequest(false); }, dataType: 'json' }); } } ko.applyBindings(viewModel); getItems(20);
A different solution using a custom binding scrolling the entire browser window:
http://figg-blog.tumblr.com/post/32733177516/infinite-scrolling-knocked-out.
Fiddler example: http://jsfiddle.net/8x4vG/2/
Use the binding like so:
<div data-bind="foreach: collection"> <div> <span data-bind="text: $index()"></span> <span data-bind="text: $data"></span> </div> </div> <div data-bind="scroll: collection().length < 160, scrollOptions: { loadFunc: addSome, offset: 10 }">loading</div>
With a View Model looking something like this:
var viewModel = function(){ this.collection = ko.observableArray([]) var disney = ["Mickey", "Donald", "Daffy", "Hewie", "Dewie", "Lewie"] var self = this; this.addSome = function(){ for(var i = 0; i < 40; i++){ self.collection.push(disney[Math.floor((Math.random()*6))]) } } this.addSome(); }
The binding implementation:
ko.bindingHandlers.scroll = { updating: true, init: function(element, valueAccessor, allBindingsAccessor) { var self = this self.updating = true; ko.utils.domNodeDisposal.addDisposeCallback(element, function() { $(window).off("scroll.ko.scrollHandler") self.updating = false }); }, update: function(element, valueAccessor, allBindingsAccessor){ var props = allBindingsAccessor().scrollOptions var offset = props.offset ? props.offset : "0" var loadFunc = props.loadFunc var load = ko.utils.unwrapObservable(valueAccessor()); var self = this; if(load){ element.style.display = ""; $(window).on("scroll.ko.scrollHandler", function(){ if(($(document).height() - offset <= $(window).height() + $(window).scrollTop())){ if(self.updating){ loadFunc() self.updating = false; } } else{ self.updating = true; } }); } else{ element.style.display = "none"; $(window).off("scroll.ko.scrollHandler") self.updating = false } } }
I thought I would share some other scrollers I have found...
https://github.com/thinkloop/knockout-js-progressive-filter
https://github.com/thinkloop/knockout-js-infinite-scroll
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With