Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

knockout virtual scrolling binding

Tags:

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?

like image 284
Homer Avatar asked Jul 19 '13 14:07

Homer


2 Answers

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     }   }  } 
like image 138
Hallvar Helleseth Avatar answered Sep 17 '22 12:09

Hallvar Helleseth


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

like image 32
Homer Avatar answered Sep 19 '22 12:09

Homer