Knockout Mapping重新渲染所有内容

我正在使用Knockout映射插件来刷新UI,每3秒从服务器检索一次JSON。 UI由一些嵌套的foreach绑定组成。 但是,即使没有任何更改,似乎所有foreach绑定中的所有内容都会被完全删除并在每次刷新时重新呈现。

 var testData = { Answers: [], Inspectable: { Categories: [{ Id: 1, Name: "Test Category", Questions: [{ Id: 1, Text: "Test Question", Active: true, Answers: [{ Text: "Test Answer", Id: 1 }] }] }] } }; function ViewModel() { var self = this; this.refreshUrl = $("[data-view=edit]").data("url"); this.refresh = function(callback) { $.get(self.refreshUrl, function(data) { //Ignoring actual JSON data for testing ko.mapping.fromJS(testData, {}, self); if (typeof callback == "function") { callback.call(self); } }); } this.addedQuestion = function() { // Gets called for every question every refresh by afterRender // Never gets called at all by afterAdd } }; var refreshing = false, handler; window.viewModel = new ViewModel(); //Initialize the UI after initial AJAX is completed viewModel.refresh(function() { ko.applyBindings(this); $(document).on("click", ".add-question", function() { if (!refreshing) { handler = setInterval(viewModel.refresh, 3000); refreshing = true; } }); }); 

有没有人看到这个明显错误?

编辑

我编辑了脚本以使用静态JavaScript对象。 它仍然会重新渲染每次刷新。 同时更新为Knockout 2.3.0。 这是观点:

   

No questions in this category. <a class="add-question" data-bind="attr: { href: '?categoryId=' + Id() + '&inProgress=true' }" target="_blank">Add some.

<a class="add-question" data-bind="text: 'New question for ' + Name(), attr: { href: '?categoryId=' + Id() + '&inProgress=true' }" target="_blank">

你的绑定被完全删除并重新渲染每次刷新的原因,即使没有任何改变是因为你每次刷新都调用ko.applyBindings

您不希望刷新函数中ko.applyBindings 。 你想调用ko.applyBindings一次,就是这样。 之后,KO将在数据更新时处理更新DOM(反之亦然)。 你只想要:

 var testDate = { ... }; function ViewModel () { ... } var viewModel = new ViewModel(); ko.applyBindings(viewModel); viewModel.refresh(function () { // ko.applyBindings(this); <- Get rid of this here, no bueno $(document).on("click", ....); }); 

就是这样。 每次调用refresh时,都会从更新viewModel的服务器获取数据。 如果值更新,KO将根据需要更新DOM。 在所有这些之后调用applyBindings时,KO会使用大刀来浏览DOM,无论是否需要更新所有绑定。


快速jQuery提示:

$.get(...)返回一个promise 。 promise返回有三个重要函数: .done(), .fail(), and .always(). 对于this.refresh()函数,返回$ .get结果,如下所示:

 this.refresh = function () { return $.get(...); }; 

然后什么叫它会这样做:

 viewModel.refresh().done(function(data){ // Callback function }); 

现在您不必传递回调函数,检查回调是否是函数类型,或者担心在发生故障时处理回调函数。 它也是通用的,你可以继续在一系列函数中返回promise,这些函数将等待$ .get请求在执行其函数之前得到解决。