将过滤器行添加到动态创建的knockout.js网格中

时间:2014-01-10 07:17:48

标签: knockout.js

我有一个用于绑定到结果表的视图模型。视图动态呈现结果表,而不需要任何先前的列数或名称知识,这很好。与描述here的情况类似,为了保持通用而非特定于域名,我已经根据这些问题回答了代码示例。

但是我需要添加一个过滤器行以允许用户进行过滤,我已根据下面代码中的列名添加了一行输入,并尝试将它们绑定到视图模型。重要的是它们绑定到视图模型,以便在刷新网格时视图模型知道应用的任何过滤器。

我尝试过几件事

  • 首先如下面的代码片段所示,我创建了一个可观察的过滤器对象,并尝试将表中的每个字段绑定到该过滤器对象上的属性。但这似乎不起作用。
  • 我尝试的另一个选项是根据列名创建一个可观察的过滤器对象数组,并将过滤器列绑定到那些似乎也不起作用的过滤器列

任何想法都将不胜感激

非常感谢,Ed

JS

var VM = function () {
  var self = this;
  self.items = ko.observableArray();
  self.filters = ko.observable({});

  self.columnNames = ko.computed(function () {
    if (self.items().length === 0)
        return [];
    var props = [];
    var obj = self.items()[0];
    for (var name in obj)
        props.push(name);
    return props;


  });

};
var vm = new VM();

ko.applyBindings(vm);

vm.items.push({
  'Name': 'John',
  'Age': 25
});
vm.items.push({
'Name': 'Morgan',
'Age': 26
});

查看:

<table>
  <thead>
    <tr data-bind="foreach: columnNames">
        <th> <span data-bind="text: $data"></span>

        </th>
    </tr>
  </thead>
  <tbody >

   <!-- add filter rows -->
    <tr data-bind="foreach: $root.columnNames">
        <td ><input type='text' data-bind="value: $root.filters[$data]"/></td>
    </tr>
   <!-- add the items -->
   <!-- ko foreach: items -->
   <tr data-bind="foreach: $parent.columnNames">
        <td data-bind="text: $parent[$data]"></td>
    </tr>
   <!-- /ko -->
  </tbody>
</table>

1 个答案:

答案 0 :(得分:4)

我做了一个小提琴,其中filters存储在一个对象{Col1 : Value1, Col2 : Value2...}中。

现在columnNames computed返回一个包含列标题及其过滤器的对象。

我还创建了一个计算的filteredItems,它只包含与过滤器匹配的项目。

subscriptions数组旨在跟踪订阅,以便在列数更改时删除它们。

 var VM = function () {
    var self = this;
    self.items = ko.observableArray();
    self.filters = ko.observable({});
    self.filteredItems = ko.computed(function () {
        var filters = self.filters();

        var items = ko.utils.arrayFilter(self.items(), function (item) {
            for (var col in filters) {
                var v = (item[col] || '').toString(); // cell value
                var f = filters[col]; // what you typed in header
                if (v.indexOf(f) < 0) return false; // filter is contains
            }
            return true;
        });
        return items;
    });
    var subscriptions = [];
    self.columnNames = ko.computed(function () {
        // clean old subscriptions
        ko.utils.arrayForEach(subscriptions, function (s) { s.dispose(); });
        subscriptions = [];
        if (self.items().length === 0) return [];
        var props = [];
        var obj = self.items()[0];
        for (var name in obj) {         
            var p = { name: name, filter: ko.observable('') };
            // subscribe : so when you type something, filterOnChanged will be invoked.
            subscriptions.push(p.filter.subscribe(filterOnChanged, p));
            props.push(p);
        }
        return props;
    });

    var filterOnChanged = function (value) {
        console.log([this.name, value]);
        var filters = self.filters();
        filters[this.name] = value;
        self.filters(filters);
    };

};

See fiddle