Knockout foreach不清除新VM上的先前条目

时间:2017-11-02 09:42:06

标签: knockout.js

我有一个模态表单,其中两个嵌套列表绑定到可观察数组。

每次单击按钮打开模态时,这两个嵌套列表都不会清除以前的数据,即使我为整个事物生成了一个全新的视图模型。我最终会在这两个列表中找到重复的(和三重的......等)项目。

如何确保在为此事物提供新视图模型时,它会清除以前的数据?

ViewModel本身很好:我可以ko.toJS(self)在每个实例上,并且数据中的所有内容都是正确的。这是绑定的一些遗留物。

这是我对该特定区域的绑定:

<div class="notes-container" data-bind="visible: showNotesContainer">

    <label>Notes</label>
    <ul data-bind="foreach: noteGroups" class="question-list">                                
        <li>
            <span class="he-question-group" data-bind="text: name"></span>
            <ul class="he-question-list" data-bind="foreach: notes">
                <li><span data-bind="text: question"></span></li>
                <li><input type="text" data-bind="value: answer" /></li>
            </ul>
        </li>
    </ul>
</div>

这是我的“基础”VM:

function hoursEntryVM(model) {

    var self = this;

    ...
    self.noteGroups = ko.observableArray(getNoteGroupsVMs(model.NoteGroups));
    ...

    var root = document.getElementById(model.rootElementId);
    ko.cleanNode(root)
    ko.applyBindings(self, root);

    return self;

    function getNoteGroupsVMs(noteGroupModel) {
        var notes = [];
        for (var i = 0; i < noteGroupModel.length; i++) {
            notes.push(new hoursNoteGroupVM(noteGroupModel[i]));
        }
        return notes;
    }       
}

在按钮上单击以打开模态我有这样的事情:

$.ajax({
    url: '/mysource',
    success: function(data) {
        data.rootElementId = 'hours-entry-container';
        var vm = new window.myProj.hoursEntry.hoursEntryVM(data);
        console.log(ko.toJS(vm));
        myModal.Show();
    }
});

2 个答案:

答案 0 :(得分:4)

由于您自己想出了处理此问题的最佳方式(使用模板),但您表示您想知道发生了什么:

引擎盖

foreach

foreach就像就地模板绑定一样。与innerHTML绑定的元素的foreach被视为模板字符串。

<{1}}做 >做什么

当你cleanNode时,淘汰不会&#34;撤消&#34;它的绑定;它只删除view(HTML)和viewmodel(js)之间的依赖关系。绑定上下文已删除。

这意味着,在cleanNode之后,用作模板的内部HTML会发生变化。

示范:

&#13;
&#13;
cleanNode
&#13;
var source = [1, 2, 3];


var applyAndClean = function() {
  var el = document.querySelector("ul");

  console.log("Applying bindings using template:");
  console.log(el.innerHTML);

  ko.applyBindings(source, el);
  ko.cleanNode(el);
}

ko.applyBindings({
  onClick: applyAndClean
}, document.querySelector("button"));
&#13;
&#13;
&#13;

按按钮应用装订并在之后清洁。控制台记录使用的模板。第一次运行时,模板包含一个 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <button data-bind="click: onClick">apply and clean</button> <ul data-bind="foreach: $data"> <li data-bind="text: $data"></li> </ul>,重复三次次。第二次运行时,模板包含三个 <li>元素,这些元素重复三次。 I.e。:列表项的数量等于<li>的{​​{1}}。

3^n绑定

的区别

模板绑​​定并不关心数据绑定元素中的内容。它只是丢弃所有n = numer of times bindings are applied并将其替换为链接的模板。

再次,就像评论者所说的那样,你永远不需要拨打template(可能是自定义绑定之外)。

答案 1 :(得分:0)

我能够使用淘汰赛template binding完成所需的行为:

<div class="notes-container" data-bind="visible: showNotesContainer">
    <label>Notes</label>

    <ul class="question-list" data-bind="template: { name: 'hours-noteGroups-template', foreach: noteGroups }"></ul>

    <script type="text/html" id="hours-noteGroups-template">
        <li><span class="he-question-group" data-bind="text: name"></span>
            <ul id="he-notes-list" class="he-question-list" data-bind="foreach: notes">
                <li><span data-bind="text: question"></span></li>
                <li><input type="text" data-bind="value: answer" /></li>
            </ul>
        </li>
    </script>

</div>

我仍然很想知道为什么最初的尝试按照它的方式行事。