使用函数分配模板时,值不会更新

时间:2014-07-17 20:41:09

标签: javascript knockout.js

我有这个HTML,并尝试使用它来生成一个表,其中包含添加更多行的选项:

<thead>
    <tr>
        <th>Item</th>
        <th>Cost</th>
        <th>Amount</th>
        <th>
            <button class="btn btn-default" data-bind="click: addItem">Add Item</button>
        </th>
    </tr>
</thead>
<tbody data-bind="foreach: items">
    <tr>
        <td data-bind="template: {name: $parent.dynTemplate, data: item }">
        <td data-bind="template: {name: $parent.dynTemplate, data: cost() }"></td>
        <td data-bind="template: {name: $parent.dynTemplate, data: amount() }">
        <td></td>
    </tr>
</tbody>

我正在使用两种不同的模板:

<script id="inpTmp" type="text/html">
    <input data-bind="value: $data" />
</script>
<script id="dispTmp" type="text/html">
    <p data-bind="text: $data"></p>
</script>

我正在根据dynTemplate函数的结果选择调用哪一个。我为此提供动力的淘汰赛非常简单:

function ItemAdd(name, icost, iamount) {
    var self = this;
    self.item = name;
    self.cost = ko.observable(icost);
    self.amount = ko.observable(iamount);
}
function TestModel() {
    var self= this;
    self.items= ko.observableArray([
        new ItemAdd("a", 5, 10),
        new ItemAdd("b", 6, 4)
    ]);
    self.addItem= function() {
        self.items.push(new ItemAdd("", 0, 0));
    };
    self.dynTemplate= function(init, s) {
        if(init=== 0 || init=== '') {
            return 'inpTmp';
        }
        return 'dispTmp';
    };
}
ko.applyBindings(new TestModel());

我遇到的问题是,当我在新创建的行中输入值时,items中的值不会改变。它们正确初始化,但是当我运行一个函数来记录items中的值时,它们仍然是默认值。如果我使用knockout if语句,那么一切都会正确更新。但是,使用6组if语句似乎不是很有效,所以我想看看是否可以将其拉出一个函数,然后发回适当的模板。当值为""或0时,我正在尝试输入,然后在输入内容时将其更改为<p>

我已尝试更改数据传递到模板的方式,我尝试使用with分配上下文,但无济于事。除非dynTemplate$root作为前缀,否则调用$parent无效。如果这正在改变上下文,有没有办法重置它?

这是上下文的问题,如果是,有没有办法用dynTemplate函数分配上下文?或者模板中新创建的元素是否未正确绑定?我搜索了很多,并在foreach循环中找到了模板,但没有看到用于应用它们的函数。如果有更好的方法,请告诉我。

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

您当前的示例无法正常工作,因为ko依赖性攻击者未发现您的模型字段已更改。这是因为&#39; init&#39;是展开的值(不是可观察的)。 这个小提琴展示了如何使它与单个项目一起使用。领域。 http://jsfiddle.net/tabalinas/VXXqr/

在这个更改版本的dynTemplate中,我们得到了observable的值,因此依赖关系跟踪器可以看到该值已更改。当然,我们需要更改模板。

self.dynTemplate= function(item, s) {
    var val = item.item();
    if(val=== 0 || val=== '') {
        return 'inpTmp';
    }
    return 'dispTmp';
};

<script id="inpTmp" type="text/html">
    <input data-bind="value: $data.item" />
</script>
<script id="dispTmp" type="text/html">
    <p data-bind="text: $data.item"></p>
</script>

对于您的情况,您需要所有字段的通用模板,您可以执行以下操作:将字段名称作为数据传递。该模板将从$ parent中获取数据。 dynTemplate func也相应更改。

<tbody data-bind="foreach: items">
    <tr>
        <td data-bind="template: {name: $parent.dynTemplate, data: 'item' }">
        </td>
        <td data-bind="template: {name: $parent.dynTemplate, data: 'cost' }">    
        </td>
        <td data-bind="template: {name: $parent.dynTemplate, data: 'amount' }">
        </td>
    </tr>
</tbody>

<script id="inpTmp" type="text/html">
    <input data-bind="value: $parent[$data]" />
</script>
<script id="dispTmp" type="text/html">
    <p data-bind="text: $parent[$data]"></p>
</script>

self.dynTemplate= function(field, context) {
    var value = context.$parent[field]();
    if(value=== 0 || value=== '') {
        return 'inpTmp';
    }
    return 'dispTmp';
};

请参阅小提琴http://jsfiddle.net/tabalinas/VXXqr/5/