在knocket js中应用绑定后,向视图模型添加新属性

adding new properties to view model after applybinding in knockout js

本文关键字:新属性 添加 模型 属性 视图 js knocket 应用 绑定      更新时间:2023-09-26

我不太擅长淘汰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"上添加一个"12>da"属性,示例值为"123"。

这成功地创建了一个新的可观察属性(我用console.log检查过)。但没有更新UI

因此,在这次点击之后,我在我的视图模型上调用了另一个函数,该函数将尝试执行ko.cleanNode($('body')[0]),然后执行ko.applyBindings(myViewModel,$('body’)[0])然后更新UI。


我的问题:

我是否必须调用clean节点,或者有更好的方法可以在视图模型更新后立即更新UI?

我的疑虑:

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

访问的帖子:向使用Knockout JS映射插件创建的视图模型添加属性
(我不太确定我是否理解这篇文章。如果推荐的话,我会再看一遍,因为我也在使用映射插件将AJAX调用的纯json响应转换为可观察的视图模型,但我的实现有点不同)

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


编辑:
为什么我需要实现这个-

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

因此,在ko.applyBinding(html元素)内部传递的最终html视图将是几个较小的html片段的UNION,这些片段将构成屏幕。

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

我希望它是清楚的。如果不是,我正在为同样的事情创建一个plunkr。将很快更新。

更新
New plunkrhttp://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中的da)。因此将显示da部分。

我认为你误解了淘汰赛的工作方式。在诸如动态列表之类的情况下,并不是所有的可观察性都会立即可用。然而,你的可观察只是模型上的一个属性。该可观测值应与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);
    },
    ...

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

在运行时添加属性需要调用应用绑定。

然而,如果你愿意放弃最初的设计,答案很简单。

我假设你的工资组成部分都有一个共同的模型,可以让你推导出它们将如何添加到工资计算中。在没有详细说明的情况下,我称之为薪酬部分。

  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的snippet来表示每个薪资组件。

因此,更改您的模型以使用可观察阵列来处理您的动态模型添加如下:

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

同样,根据这篇文章最初的发布方式,不完全确定这是你想要的。