淘汰赛映射重新渲染一切 [英] Knockout Mapping re-rendering everything

查看:109
本文介绍了淘汰赛映射重新渲染一切的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是淘汰赛映射插件,刷新JSON的UI从每3秒服务器检索。用户界面包括一些嵌套的的foreach 绑定。然而,似乎一切都在所有的的foreach 绑定得到彻底删除和重新渲染每刷新,即使没有发生任何变化。

  VAR TESTDATA = {
    回答:[],
    视察:{
        类别:[{
            ID:1,
            产品名称:测试分类,
            问题:[{
                ID:1,
                文字:试题,
                活动:真正的,
                回答:[{
                    文字:测试答案,
                    ID:1
                }]
            }]
        }]
    }
};

功能视图模型(){

    无功自我=这一点;

    this.refreshUrl = $([数据视图=编辑])的数据(URL)。

    this.refresh =函数(回调){
        $获得(self.refreshUrl,功能(数据){
            //忽略的实际JSON数据进行测试
            ko.mapping.fromJS(TESTDATA,{},个体经营);
            如果(typeof运算回调==功能){
                callback.call(个体经营);
            }
        });
    }

    this.addedQuestion =功能(){
        //获取呼吁每一个问题每次刷新由一个AfterRender
        //不会被调用都通过afterAdd
    }

};

VAR清爽=假,处理程序;
window.viewModel =新视图模型();

//初始化界面后的初始AJAX完成
viewModel.refresh(函数(){

    ko.applyBindings(本);

        $(文件)。在(点击,。新增-问题,函数(){
        如果(!清爽){
            处理器= setInterval的(viewModel.refresh,3000);
            清爽= TRUE;
        }
    });
});
 

有谁看到什么错得离谱这个?

修改

我编辑使用静态JavaScript对象的脚本。它还重新呈现每次刷新。也更新到淘汰赛2.3.0。这里的观点:

 <  - 阁的foreach:Inspectable.Categories  - >
        < D​​IV CLASS =排排液空间上面的>
            < H4类=橙色数据绑定=文字:名称>< / H4>
            !<  - 阁的foreach:{数据:问题,一个AfterRender:$ root.addedQuestion}  - >
                !<  - 如果阁:活动()|| 〜$ .MAP($ root.Answers()函数(){返回a.Id()== ID()}) - >
                    < D​​IV CLASS =问题空间上面的>
                        < P><强大的数据绑定=文本:>< / STRONG>< / P>
                        < D​​IV CLASS =答案数据绑定=的foreach:答案>
                            <  - 柯若:$ parent.AllowMultiple  - ><标签类=复选框><输入类型=复选框数据URL =<%= Url.Action(AddOrRemoveAnswer )%>中数据绑定=ATTR:{值:ID,名称:问卷+ $ parent.Id()}/><  - 柯文:!文本 - ><  -  /阁 - >< /标签><! -  /高 - >
                            !<  - 阁如不方便:$ parent.AllowMultiple  - ><标签类=无线电><输入类型=无线电数据URL =<%= Url.Action(AddOrRemoveAnswer )%>中数据绑定=ATTR:{值:ID,名称:问卷+ $ parent.Id()}/><  - 柯文:!文本 - ><  -  /阁 - >< /标签><! -  /高 - >
                        < / DIV>
                    < / DIV>
                <! -  /高 - >
            <! -  /高 - >
            !<  - 如果阁:问题()长度== 0  - >
                < D​​IV CLASS =问题空间上面的>
                    < P><强>的问题这一类与< / STRONG> <一类=附加问题数据绑定=ATTR:{HREF:'<%= Url.Action(创建,问)%>的categoryId =?'+ ID()+' &功放; INPROGRESS =真正的'}目标=_空白>添加一些< / A> &所述; / P>
                < / DIV>
            <! -  /高 - >
            !<  - 如果阁:问题()长度GT; 0  - >
                < D​​IV CLASS =问题空间上面的>
                    <一类=附加问题数据绑定=文字+姓名(新问题),ATTR:{HREF:'<%= Url.Action(创建,问题)% >的categoryId ='+ ID()+'&放大器; INPROGRESS =真正的'}目标=_空白>< / A>
                < / DIV>
            <! -  /高 - >
        < / DIV>
    <! -  /高 - >
 

解决方案

您的绑定也越来越彻底删除和重新渲染每刷新,即使什么都没有改变的原因是因为你调用 ko.applyBindings 每次刷新。

您不想 ko.applyBindings 的刷新功能的内部。要呼叫ko.applyBindings一次,仅此而已。在此之后,将正处理更新的DOM当数据更新(或反之亦然)。你只是想:

  VAR testDate = {...};
功能视图模型(){...}
VAR视图模型=新视图模型();
ko.applyBindings(视图模型);
viewModel.refresh(函数(){
  // ko.applyBindings(本); <  - 摆脱这种在这里,没有布埃诺
  $(文件)。在(点击,....);
});
 

就是这样。每次你叫了刷新,您从更新视图模型服务器获取数据。 KO反过来将更新DOM是必要的,如果值更新。当你调用毕竟是applyBindings,正经历一个大刀的DOM,更新所有的绑定是否需要与否。


快速jQuery的提示:

$。获得(...)返回承诺。有三个重要的功能是一个承诺的回报, .done(),.fail(),和。总是()。为你的 this.refresh ()函数,返回$不用彷徨的结果是这样的:

  this.refresh =功能(){
  返回$获得(...);
};
 

然后什​​么都调用它会做这样的:

  viewModel.refresh()。完成(功能(数据){
  //回调函数
});
 

现在你不必传递一个回调函数,检查是否回调函数类型,也不用担心操作的回调函数在出现故障的情况下。这也是普遍的,你可以继续返回倒链,将所有等待直到在$不用彷徨请求函数承诺解决他们履行自己的功能之前。

I'm using the Knockout mapping plug-in to refresh the UI with JSON retrieved from the server every 3 seconds. The UI consists of some nested foreach bindings. However, it seems that everything in all the foreach bindings are getting completely deleted and re-rendered with every refresh, even when nothing has changed.

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;
        }
    });
});

Does anyone see anything glaringly wrong with this?

EDIT

I edited the script to use a static JavaScript object. It still re-renders every refresh. Also updated to Knockout 2.3.0. Here's the 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 -->

解决方案

The reason your bindings are getting completely deleted and re-rendered with every refresh, even when nothing has changed is because you're calling ko.applyBindings every refresh.

You do not want ko.applyBindings inside of your refresh function. You want to call ko.applyBindings once and that's it. After that, KO will handle updating the DOM when the data updates (or vice versa). You just want:

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", ....);
});

And that's it. Every time you've been calling refresh, you get data from the server that updates the viewModel. KO in turn will update the DOM as necessary if values update. When you call applyBindings after all that, KO goes through the DOM with a broadsword, updating all of your bindings whether it needs to or not.


Quick jQuery Tip:

$.get(...) returns a promise. There are three important functions that a promise returns, .done(), .fail(), and .always(). For your this.refresh() function, return the $.get result like this:

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

Then what ever calls it would do this:

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

Now you don't have to pass a callback function, check if callback is type of function, or worry about handling the callback function in the event of a failure. It's also universal and you can continue returning the promise down a chain of functions that will all wait til the $.get request is resolved before they perform their function.

这篇关于淘汰赛映射重新渲染一切的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆