我使用 Knockout 映射插件每 3 秒从服务器检索一次 JSON 来刷新 UI。 UI 由一些嵌套的 foreach
绑定(bind)组成。然而,似乎所有 foreach
绑定(bind)中的所有内容都被完全删除,并在每次刷新时重新渲染,即使没有任何更改。
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。这是 View :
<!-- ko foreach: Inspectable.Categories -->
<div class="row row-fluid space-above">
<h4 class="orange" data-bind="text: Name"></h4>
<!-- ko foreach: { data: Questions, afterRender: $root.addedQuestion } -->
<!-- ko if: Active() || ~$.map($root.Answers(), function(a) { return a.Id() == Id() }) -->
<div class="question space-above">
<p><strong data-bind="text: Text"></strong></p>
<div class="answers" data-bind="foreach: Answers">
<!-- ko if: $parent.AllowMultiple --><label class="checkbox"><input type="checkbox" data-url="<%= Url.Action("AddOrRemoveAnswer") %>" data-bind="attr: { value: Id, name: 'question-' + $parent.Id() }"/><!-- ko text: Text --><!-- /ko --></label><!-- /ko -->
<!-- ko ifnot: $parent.AllowMultiple --><label class="radio"><input type="radio" data-url="<%= Url.Action("AddOrRemoveAnswer") %>" data-bind="attr: { value: Id, name: 'question-' + $parent.Id() }"/><!-- ko text: Text --><!-- /ko --></label><!-- /ko -->
</div>
</div>
<!-- /ko -->
<!-- /ko -->
<!-- ko if: Questions().length == 0 -->
<div class="question space-above">
<p><strong>No questions in this category.</strong> <a class="add-question" data-bind="attr: { href: '<%= Url.Action("Create", "Questions") %>?categoryId=' + Id() + '&inProgress=true' }" target="_blank">Add some.</a> </p>
</div>
<!-- /ko -->
<!-- ko if: Questions().length > 0 -->
<div class="question space-above">
<a class="add-question" data-bind="text: 'New question for ' + Name(), attr: { href: '<%= Url.Action("Create", "Questions") %>?categoryId=' + Id() + '&inProgress=true' }" target="_blank"></a>
</div>
<!-- /ko -->
</div>
<!-- /ko -->
最佳答案
即使没有任何更改,您的绑定(bind)也会在每次刷新时被完全删除并重新渲染,这是因为您每次刷新时都会调用 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", ....);
});
就是这样。每次调用刷新时,您都会从更新 viewModel 的服务器获取数据。如果值更新,KO 会根据需要更新 DOM。当您在完成所有这些之后调用 applyBindings 时,KO 将使用大刀遍历 DOM,更新所有绑定(bind)(无论是否需要)。
<小时/>快速 jQuery 提示:
$.get(...)
返回 promise 。 Promise 返回三个重要的函数:.done()、.fail() 和 .always()。
对于 this.refresh()
函数,返回$.get 结果如下:
this.refresh = function () {
return $.get(...);
};
然后调用它就会执行以下操作:
viewModel.refresh().done(function(data){
// Callback function
});
现在您不必传递回调函数,检查回调是否是函数类型,也不必担心在失败时处理回调函数。它也是通用的,您可以继续沿着一系列函数返回 promise ,这些函数都将等到 $.get 请求得到解决后才执行其函数。
关于javascript - Knockout Mapping 重新渲染一切,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18219830/