Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically refresh list view on change - knockoutjs & JQuery Mobile

I am using knockoutjs (very new to it) with JQuery Mobile. I have a listview which I bind filtered results to. After I load my data the first time I have to call

$('ul').listview('refresh');

in order for JQM to restyle my list, this works great.

However when I filter my list, it is rerendered and looses the style again and I can't figure out where to call the refresh again.

My html is as follows:

<p>Filter: <input data-bind="value: filter, valueUpdate: 'afterkeydown'" /></p>
     <ul data-role="listview" data-theme="g" data-bind="template: {name: 'myTemplate', foreach: filteredItems }" />

My Knockout JS is:

var car = function (name, make, year) {
    this.name = name;
    this.make = make;
    this.year = year;
}

var carsViewModel = {
    cars: ko.observableArray([]),
    filter: ko.observable()
};

//filter the items using the filter text
carsViewModel.filteredItems = ko.dependentObservable(function () {
    var filter = this.filter();
    if (!filter) {
        return this.cars();
    } else {
        return ko.utils.arrayFilter(this.cars(), function (item) {
            return item.make == filter;
        });
    }
}, carsViewModel);

function init() {
    carsViewModel.cars.push(new car("car1", "bmw", 2000));
    carsViewModel.cars.push(new car("car2", "bmw", 2000));
    carsViewModel.cars.push(new car("car3", "toyota", 2000));
    carsViewModel.cars.push(new car("car4", "toyota", 2000));
    carsViewModel.cars.push(new car("car5", "toyota", 2000));        
    ko.applyBindings(carsViewModel);
    //refresh the list to reapply the styles
    $('ul').listview('refresh');
}

I am sure that there is something very silly that I am missing...

Thank you for your time.

like image 227
jimjim Avatar asked Aug 30 '11 16:08

jimjim


3 Answers

This issue has come up on the KO forums a few times.

One option is to create a binding that is bound to your filteredItems and runs the listview refresh.

It could look like:

   ko.bindingHandlers.jqmRefreshList = { 
     update: function(element, valueAccessor) { 
       ko.utils.unwrapObservable(valueAccessor()); //just to create a dependency
       $(element).listview("refresh"); 
     } 
   };

Now, you would place this on the container (or really on any element) and pass in the observable that you want it to depend on like:

<ul data-bind="jqmRefreshList: filteredItems"></ul>
like image 190
RP Niemeyer Avatar answered Nov 08 '22 06:11

RP Niemeyer


Can you post the entire working code on jsfiddle ? Because I am having the same issue and I tried your solution but it still not working.

[Edit] : Ok, it worked fine for me like this :

ko.bindingHandlers.jqmRefreshList = {
    update: function (element, valueAccessor) {

        ko.utils.unwrapObservable(valueAccessor()); //just to create a dependency
        setTimeout(function () { //To make sure the refresh fires after the DOM is updated 
            $(element).listview();
            $(element).listview('refresh');
        }, 0);
    }
};
like image 31
max2817 Avatar answered Nov 08 '22 07:11

max2817


Building on the previous two answers, here is something a little more complete. It allows you to use containerless binding (i.e. foreach within comments), and soles the issue of refresh being fired after the jQM page lifecycle by handling exceptions rather than a timeout:

ko.virtualElements.allowedBindings.updateListviewOnChange = true;
ko.bindingHandlers.updateListviewOnChange = {
  update: function (element, valueAccessor) {
    ko.utils.unwrapObservable(valueAccessor());  //grab dependency

    var listview = $(element).parents()
                             .andSelf()
                             .filter("[data-role='listview']");

    if (listview) {
      try {
        $(listview).listview('refresh');
      } catch (e) {
        // if the listview is not initialised, the above call with throw an exception
        // there doe snot appear to be any way to easily test for this state, so
        // we just swallow the exception here.
      }
    }
  }
};

There's a complete worked example up on my blog. Hope that helps!

like image 1
ColinE Avatar answered Nov 08 '22 07:11

ColinE