自动刷新列表视图的方式 - knockoutjs & JQuery Mobile

6
我正在使用knockoutjs(非常新手)与JQuery Mobile。我有一个列表视图,我将过滤的结果绑定到它上面。在第一次加载完数据之后,我必须调用
$('ul').listview('refresh');

为了让JQM重新设置我的列表样式,这很好用。然而,当我筛选列表时,它会重新渲染并且再次失去样式,我无法确定在哪里再次调用刷新。我的HTML如下:
<p>Filter: <input data-bind="value: filter, valueUpdate: 'afterkeydown'" /></p>
     <ul data-role="listview" data-theme="g" data-bind="template: {name: 'myTemplate', foreach: filteredItems }" />

我的 Knockout JS 是:
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');
}

我确信我错过了某个非常傻的东西...谢谢您的时间。
3个回答

14

这个问题在KO论坛上已经出现过几次。

一个解决方案是创建一个绑定,将其绑定到你的filteredItems并运行listview刷新。

它可能看起来像:

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

现在,您需要将这个绑定放在容器上(或实际上是任何元素上),并传入您想要它依赖的可观察对象,例如:

<ul data-bind="jqmRefreshList: filteredItems"></ul>

谢谢,我之前看到过这个,但是我不确定如何将它应用于我的foreach循环? - jimjim
实际上,您可以将其放在任何元素上,甚至是body。如果您想将其保留在模板中,则可以执行以下操作:data-bind="template: {name: 'myTemplate', foreach: filteredItems }, jqmRefreshList: filteredItems" - RP Niemeyer
非常感谢RP!太有效了。顺便说一下,knockmeout是一个很棒的网站。 - jimjim
在我尝试将$(element).listview("refresh")包裹在try/catch中以忽略第一次调用时的初始化问题后,上述方法对我有效。否则,在这里@Niemeyer的出色工作! - CodeMonkeyKing

3

你能在jsfiddle网站上发布完整的工作代码吗?因为我遇到了同样的问题,尝试了你的解决方案但仍然不起作用。

[编辑]:好的,我按照以下方式顺利解决了:

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);
    }
};

这让我免于把我的笔记本扔出窗外,谢谢! - David Masters
在我的情况下,我返回了一个ObservableArray。因此为了使用它,我需要执行以下操作:data-bind="template: {name: 'myTemplate', foreach: filteredItems() }" - DATEx2

1

在前两个答案的基础上,这里提供了更完整的解决方案。它允许您使用无容器绑定(即在注释中使用foreach),并通过处理异常而不是超时来解决刷新在jQM页面生命周期后触发的问题:

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.
      }
    }
  }
};

我的博客上有一个完整的工作示例。希望能帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接