knockout.js递归绑定

时间:2013-03-20 18:19:14

标签: binding knockout.js

我正在尝试与淘汰赛进行一些复杂的绑定(至少对于像我这样的新手)。

考虑以下数据:

var originalData = {
id: 1,
name: "Main",
children: [ { id: 2, name: "bob", children: []}, { id: 3, name: "ted", children: [{id: 5, name:"albert"}, {id: 9, name: "fred"}]} ],
selectedChild:  { id: 2, name: "bob" }
};

<table>
<tr>
    <td data-bind="text: name"></td>
</tr>
<tr data-bind="if: children().length > 0">
    <td>
        <select data-bind="options: children,
            optionsText: function(item){
                return item.name;
                    }, 
            optionsCaption: 'Choose...'"></select>       
    </td>
</tr>

好的,这很容易。

困难的部分是,无论何时在列表中选择某个项目,如果此项目有子项,则下方会出现一个新的选择框。其数据源将是第一个选择框中所选项目的子项。当然,它可以继续保持任何深度。

我应该如何解决这个问题?

我在jsfiddle上汇总了我目前的样本:http://jsfiddle.net/graphicsxp/qXZjM/

1 个答案:

答案 0 :(得分:9)

您可以将模板放入script标记,以便在淘汰赛中使用递归模板。 script标记中的模板可以引用自己,如下所示:

<div data-bind="template: 'personTemplate'"></div>

<script type="text/ko" id="personTemplate">
    <span data-bind="text: name"></span>
    <select data-bind="options: children, optionsText: 'name', optionsCaption: 'Choose',  value: selectedChild"></select>
    <!-- ko if: selectedChild -->
    <div data-bind="template: { name: 'personTemplate', data: selectedChild }"></div>
    <!-- /ko -->
</script>

以下是the fiddle


更新

您可以使用computed轻松执行此操作,并从视图中删除逻辑(在这种情况下我认为更好),然后将if绑定到它。

self.showChildren = ko.computed(function() {
    return self.selectedChild()
        && self.selectedChild().children().length > 0;
});

如果你想将两者放在if区块中,你可以,你只需要包括parens。原因是可观察性是功能;如果您只是使用单个引用,则knockout允许您排除它们,但是它们需要“向下钻取”到它们的属性。

if: selectedChild() && selectedChild().children().length > 0

以下是updated fiddle