【问题标题】:Knockout Mapping re-rendering everythingKnockout Mapping 重新渲染一切
【发布时间】:2013-08-15 16:52:21
【问题描述】:

我使用 Knockout 映射插件每 3 秒使用从服务器检索的 JSON 刷新 UI。 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 对象。它仍然重新渲染每次刷新。还更新到淘汰赛 2.3.0。这是视图:

    <!-- 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 -->

【问题讨论】:

  • 我没有发现任何明显的问题会导致您的问题。唯一的问题是您似乎没有在任何地方将 refreshing 设置回 false 。无论如何,重现此问题的一些查看代码和模拟数据将帮助我们帮助您。
  • 您是否尝试过“隔离”问题?我的意思是删除一些绑定以指出问题。

标签: javascript jquery ajax knockout.js knockout-mapping-plugin


【解决方案1】:

您的绑定在每次刷新时都会被完全删除并重新渲染,即使没有任何变化,原因是您每次刷新都调用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", ....);
});

就是这样。每次调用刷新时,都会从更新视图模型的服务器获取数据。如果值更新,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
});

现在您不必传递回调函数,检查回调是否是函数类型,或者担心在失败时处理回调函数。它也是通用的,您可以继续沿一系列函数返回承诺,这些函数都将等待 $.get 请求得到解决,然后再执行其功能。

【讨论】:

  • 我现在完全改变了这个功能,但这一切听起来都不错。谢谢。
  • 考虑到发布日期可能是这种情况。很高兴您能找到解决方案。
猜你喜欢
  • 2013-12-24
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
相关资源
最近更新 更多