带有Foreach的KO模板如果条件导致afterAdd不要触发

时间:2013-04-05 00:22:38

标签: knockout.js knockout-2.0

在下面的示例中,您将看到doSomething永远不会触发。如果从模板绑定中删除if: Comments,则会按预期触发。有谁知道导致这种情况发生了什么?在模板绑定处理程序上使用data属性时也会发生这种情况。

我目前正在使用Knockout 2.2.1。 jsfiddle http://jsfiddle.net/YADzx/2/

<div data-bind="template: { if: Comments, name: 'comments' }"></div>

<script type="tmpl" id="comments">
    <div data-bind="foreach: { data: Comments, afterAdd: $root.doSomething }">
        <div data-bind="text: name"></div>
    </div>
</script>
<script>
var vm = {
    Comments: ko.observableArray([{name:'hey'}]),
    doSomething: function (element, index, data) {
        $(element).addClass('wow');
    }
};

ko.applyBindings(vm);
vm.Comments.push({name:'foo'});
vm.Comments.push({name:'bar'});
</script>

1 个答案:

答案 0 :(得分:10)

if绑定上的template条件会导致Comments更改时更新。然后Knockout将重新呈现整个模板,并且foreach绑定的先前状态将丢失。

根据您想要或不想要的副作用,有几种方法可以解决这个问题。

  1. 删除if选项。您的代码仍然可以使用,但您的HTML中会<div>绑定foreach。因此,如果弄乱你的布局,这不是一个好的选择。

  2. if拆分template,并使用if绑定使用其他元素(或注释语法)。只要您使用的是Knockout 2.2.0或更高版本,这将有效。

    <script type="tmpl" id="comments">
        <!--ko if: Comments-->
        <div data-bind="foreach: { data: Comments, afterAdd: $root.doSomething }">
            <div data-bind="text: name"></div>
        </div>
        <!--/ko-->
    </script>
    
  3. 使用if绑定代替使用visible绑定,该绑定会隐藏当前元素并且不会重新呈现。

    <script type="tmpl" id="comments">
        <div data-bind="visible: Comments, foreach: { data: Comments, afterAdd: $root.doSomething }">
            <div data-bind="text: name"></div>
        </div>
    </script>
    
  4. 但要考虑的一件事是,observableArray通常不会包含假值。那是因为在JavaScript中,空数组仍然是真的。如果您要测试空数组,则需要从if: Comments更改为if: Comments().length