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开发者_StackOverflow社区 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.
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>
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);
}
};
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!
精彩评论