【问题标题】:adding new properties to view model after applybinding in knockout js在淘汰赛js中应用绑定后向视图模型添加新属性
【发布时间】:2015-04-05 10:11:42
【问题描述】:

我不太擅长淘汰 js,所以我可能错过了一些东西。

我的用例:

我有一个简单的视图模型。我的页面看起来像这样

     <body>
    <hr />
    <div>
      <label for="">
            Basic :</label>
      <input type="text" name="" data-bind="value: basic" id="txtBasic" />
    </div>
    <div>
      <label for="">
            HRA :</label>
      <input type="text" name="" data-bind="value: hra" id="txtHra" />
    </div>
    <div>
      <div style="background-color:silver;">
        <hr />
        <label for="">
          <input type="button" data-bind="click : generateModelValue" value="Generate Runtime Property" />
          <input type="button" data-bind="click : tryRebind" value="Try Rebinding with clean node" />
<br>
                DA :</label>
         <input type="text" name="" id="txtDa" data-bind="value: $data.da"><br><br></div>

      </div> 
      <hr />
      <div>
        <label for="">
                Tax :</label>
        <input type="range" name="" id="rangeTax" min="0" max="30" value="0" data-bind="value: tax" />
        <span id="spanTax">[Tax%]</span>
      </div>
      <div>
        <input type="button" value="Calculate" id="btnCalculate" data-bind="click: computeSalary" />
      </div>
      <div>
        <div id="divResult" data-bind="text: salary">
                [Salary]</div>
      </div>
    </div>
    <script>

            myViewModel={
                basic: ko.observable(1000),
                hra: ko.observable(10),

                tax: ko.observable(10),
                salary: ko.observable('Yet to be calculated'),
                computeSalary: function () {
                    this.salary(this.basic()+this.da()+this.hra());
                },
                generateModelValue: function () {
                  debugger;
                    this.da=ko.observable("123");
                },
                tryRebind: function () {
                  debugger;
                  alert("Why do i have to call this to update the view model");
                    ko.cleanNode($('body')[0]);
                    ko.applyBindings(myViewModel,$('body')[0]);
                }
            };

            ko.applyBindings(myViewModel,$('body')[0]);


        </script>
  </body>

我想在运行时添加一个属性(在本例中为“da”)。因此,为了使示例易于阅读,我将在我的模型上调用“generateModelValue”函数,该函数将添加“myViewModel”上的“da”属性,样本值为“123”。

这成功地创建了一个新的 observable 属性(我检查了 console.log)。 但不更新 UI

所以在单击之后,我在视图模型上调用了另一个函数,该函数将尝试执行 ko.cleanNode($('body')[0]) 后跟 ko .applyBindings(myViewModel,$('body')[0]); 然后更新 UI。


我的问题:

我必须调用干净节点还是有更好的方法可以在视图模型更新后立即更新 UI?

我的疑惑:

  1. 我不认为使用干净节点是实现此目的的好方法吗?
  2. 如果对象太复杂或太大,是否会导致任何性能问题。
  3. 我正在使用 "&lt;input type="text" name="" id="txtDa" data-bind="value: $data.da"&gt;" 在我的 HTML 中(这样当我使用 viewModel 中不可用的属性调用 applyBinding 时不会引发未定义的错误)
    真的需要$data(还有其他选择吗?)

访问过的帖子: Adding properties to the view model created by using the Knockout JS mapping plugin
(我不太确定我是否理解这篇文章。如果推荐的话会再看一遍,因为我也使用映射插件将纯 json 响应从 AJAX 调用转换为可观察视图模型,但我的实现是有点不同)

Live Plunker: http://plnkr.co/edit/4EwSdKihVak1dGhuobbi?p=preview


已编辑:
为什么我需要实现这一点-

因为在我调用 ko.applybinding 时,我的 viewModel 总是小于我的 HTML 标记中所需的数据绑定属性,因此会抛出未定义的错误(我使用了 $data以避免此错误)。

因此,在 ko.applyBinding(html-element) 中传递的最终 html 视图将是构成屏幕的几个较小的 html sn-ps 的 UNION。

并且不可能在调用应用绑定时收集所有视图模型属性,因为视图模型的复杂性会随着用户交互(Ajax 调用)而增加

我希望它清楚。如果没有,我正在为此创建一个 plunkr。很快就会更新。

更新
新plunkr http://plnkr.co/edit/8PNHk25jl2xig0GLyqQq?p=preview

在上面的 plunkr 中带有

的部分
<div data-bind="visible: $data.da">
         You will see this section only if the da property is available on the view model
         </div>

将在应用绑定时存在于 DOM 中,但 “da”的值不会。 并且在某些用户交互之后,视图模型将被更新,因为对象将通过 ajax 调用接收新属性(例如 plunkr 上的 tha 中的 da)。因此将显示 da 部分。

【问题讨论】:

    标签: javascript model-view-controller knockout.js viewmodel knockout-mapping-plugin


    【解决方案1】:

    我认为您误解了淘汰赛的工作方式。在某些情况下,例如动态列表等,并非所有可观察对象都会立即可用。但是,您的 observable 只是模型上的一个属性。这个 observable 应该与basichra 一起创建。延迟它的创建没有任何好处。

    将您的代码更改为:

    myViewModel = {
        basic: ko.observable(1000),
        hra: ko.observable(10),
        da: ko.observable(null),
    

    如果你想表示直到函数generateModeValue 才设置值,那么让null 表示这一点或创建另一个函数可以设置的布尔可观察对象。例如:

    myViewModel = {
        basic: ko.observable(1000),
        hra: ko.observable(10),
        da: ko.observable(null),
        daIsSet: ko.observable(false),
        ...
        generateModelValue: function () {
            debugger;
            this.da("123");
            this.daIsSet(true);
        },
        ...
    

    同样,可以动态添加可观察对象(使用数组或其他方法),但这种情况不需要那种功能。希望这可以为您澄清一些概念。

    【讨论】:

    • 好的,我简化了我的实际问题,以便我可以清晰地传达它。但实际情况要大得多。该解决方案有 2 个方面(开发和实现)HTML 模板将始终存在(它的联合 - 比如说 4-5 个不同的视图)并且它的 不可能 提供空值或空模型,因为属性键值将动态生成,通过使用 jquery 扩展,我将创建具有所需属性的合并对象 - 在此基础上将显示 dom。如果不清楚,我可以用更好的描述和实时 plunkr 编辑我的帖子
    • 我不确定您的更改是否能解决问题。您是否好奇为什么这对于纯粹的学术原因不起作用?如果你愿意,我可以解释。然而,正如我已经说过的,这里要吸取的重要教训是,你的方法是有缺陷的,应该避免。
    • @ankur - 你的例子跨越了两种不同的方法,所以我真的不知道你在做什么。您说属性键值是动态生成的,这很好。但是您的 javascript 函数具有对“动态”键 da 的硬编码引用。这里:this.salary(this.basic()+this.da()+this.hra()); 如果da 是动态的,那么您希望如何更新 javascript 以在计算中包含其他动态字段?
    • 请忽略计算中的 this.da() 引用。这是一个疏忽。
    • 我还更新了我的问题,更好地解释了用例。请看一下。谢谢
    【解决方案2】:

    在运行时添加属性将要求您调用应用绑定。

    但是,如果您愿意放弃最初的设计,答案很简单。

    我假设您的工资组件都有一个通用模型,可以让您推导出它们将如何添加到工资计算中。没有详细信息,我将其称为薪水部分。

      function salaryComponent(n,v,t){
           this.Name = ko.observable(n);
           this.Value = ko.observable(v);
           this.Type = ko.observable(t);
       }
    

    如果您需要按类型自定义显示,我会在薪水组件中添加一个类型描述符,然后使用

    <div data-bind="foreach: salaryComponents">
        <!-- ko if: type() == 1 -->
           <data-bind="template: {name:'Da-template',data:$data}
       <!-- /ko -->
    </div>
    

    在您的数组中为每个薪金组件类型应用一个模板。这将允许您构建 html 片段来表示每个工资组件。

    所以改变你的模型以使用一个可观察的数组来处理你的动态模型添加如下:

       myViewModel={
                basic: ko.observable(1000),
                hra: ko.observable(10),
    
                tax: ko.observable(10),
                salary: ko.observable('Yet to be calculated'),
                //dynamic salary components 
                salaryComponents: ko.observableArray(),
    
                computedSalary = ko.computed(function(){
                    var base = this.basic()+this.hra();
                    ko.utils.arrayForEach(salaryComponents(), function(item) {
                        base+=item.Value()
                    });
                    return base;
                }
                generateModelValue: function () {
                   salaryComponents.push(new salaryComponent('Da',123,1));
                },
            };
    

    为您的模型使用这种设计允许按薪水类型使用多个模板来创建复杂的 UI 显示,并允许您将组件添加到您的视图模型中,而无需您再次调用应用绑定。

    哦,最后一件事,没有理由必须调用计算来确定工资。改用计算值:

      computedSalary = ko.computed(function(){
                    var base = this.basic()+this.hra();
                    ko.utils.arrayForEach(salaryComponents(), function(item) {
                        base+=item.Value()
                    });
                    return base;
       }
    

    同样,根据最初发布的方式,不能完全确定这是您要查找的内容。

    【讨论】:

    • 我不认为我完全理解...但据我所知 //动态薪金组件salaryComponents: ko.observableArray(), this 将是一个严重的开销因为数据提供者服务现在必须生成薪水组件数组,当他们必须提供的只是 JSON 中的一个额外的 da 属性 时,这看起来很模糊。
    猜你喜欢
    • 2015-07-27
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    • 2018-07-11
    相关资源
    最近更新 更多