0

设置:

我有一个 knockout.js 应用程序,它使用带有“foreach: $data.items”的模板显示一个表。

$data 使用数据绑定设置,如下所示:

<div data-bind="template: {name: 'table-custom', data: {table: 'item-list-custom', config: $root.items, default: {foo: '', bar: ''}}}"></div>

$root.items 是一个字典数组,如下所示:

[{foo: 'val2', bar: 'val2'}, ...]

我从 JSON 中获取 $root.items 中的值,并根据模板创建表。

问题:

我想在表中添加一个新列,所以我在“默认”字典中添加了一个默认值(例如 baz:'')。新列呈现为选择(下拉列表)。

一切都很好。我的问题是:

1)如果可用,我如何设置所选选项的值?我试过了

<select data-bind="value: baz, ...

但它抱怨是因为现有的行(来自 JSON)还没有包含 baz 键,所以它找不到它。

2)当我在选择中选择某个值时,对于现有行,它不会与模型的其余部分一起保存。即它们仍然只包含“foo”和“bar”键。

如果我在表中添加一个新行,然后选择一个值,它可以正常工作,并将 baz 值与其他值一起保存。我猜这是因为“默认” baz 值适用于新行,但不适用于现有行。

那么,我如何让这个设置与我现有的数据(加载时没有“baz”属性,因为我稍后将其添加到表中)一起使用新行?

4

2 回答 2

0

您可能应该做的是将您的视图模型逻辑与模板分离,将其封装在一个类中,然后将其传递给模板。这使您可以处理各种事情,例如将默认值设置为您需要的任何值(随着新列的添加或服务器端 JSON 结构的更改),并且还使视图模型更具可测试性。它还使您能够非常轻松地实现诸如客户端编辑/添加/删除行数据之类的事情。至于第 2 点,我相信在视图模型中将其设为 ko.observable 将解决此问题。

这是一个可能的实现的片段:

function TableDefinition(tableName, tableConfig, options) {
    var self = this;
    tableConfig = tableConfig || {};

    // Create an instance of TableRow from each item in tableConfig
    var initialItems = ko.utils.arrayMap(tableConfig || [], 
                                       function(item) { return new TableRow(item); });
    self.config = ko.observableArray(initialItems);
    self.tableName = ko.observable(tableName);

    self.addRow = function() {
        // Allows you to instantly add a new row right from your page without relying on
        // the server-side structure
        self.config.push(new TableRow());
    };
    self.deleteRow = function(row) {
        self.config.remove(row);
    }
}

function TableRow(data) {
    var self = this;
    data = data || {};
    self.foo = ko.observable(data.foo || ''); // These are observables so that
    self.bar = ko.observable(data.bar || ''); // you can bind the values from
    self.baz = ko.observable(data.baz || ''); // control to view model
    self.selections = ['val1', 'val2', 'val3', 'val4']
}

现在您可以将其添加到您的根视图模型中,并将来自服务器的数据直接传递到TableDefinition视图模型中。

function RootViewModel(data) {
    var self = this;    
    self.table = new TableDefinition('item-list-custom', data);
}

在您的页面上:

var dataFromServer = [
    {foo: 'val1', bar: 'val1'},
    {foo: 'val2', bar: 'val2'},
    {foo: 'val3', bar: 'val3'},
    {foo: 'val4', bar: 'val4'}]; // Dummy data, assumed to be retrieved from the server

var viewModel = new RootViewModel(dataFromServer);
ko.applyBindings(viewModel, document.getElementById('root'));

这是相关的 JsFiddle:http: //jsfiddle.net/dflor003/BM3HU/

底部有一个实时调试视图,其中包含您将以 JSON 形式发送回服务器的数据输出,当您更改值时会更新这些数据。

于 2012-10-31T18:15:16.147 回答
0

您应该能够通过在您的属性前面添加以下内容来做到这一点$data

<select data-bind="value: $data.baz, ...

我创建了一个小的 JsFiddle 来演示:http: //jsfiddle.net/amtiskaw/HD2jt/

于 2012-09-20T06:15:57.320 回答