Knockout Computed Observable仅识别一个Observable

时间:2017-12-13 00:43:17

标签: knockout.js

背景:我正在使用Knockout 3.4.0开发网页。在页面上,我使用计算的observable来计算费用的成本(以美元计)。费用可以是百分比或统一费率,并且可以将此百分比/统一费率信息插入两个文本框中的一个。我使用单选按钮和jQuery为用户选择哪个文本框处于活动状态,因为用户只能选择百分比统一费率。我也使用JSON和ko.mapping加载视图模型,但这似乎不是问题。我还应该提到客户端的目标浏览器是IE11或Edge。

问题:计算出的observable似乎没有订阅统一费率文本框中的更改。当我在我的localhost上运行应用程序(应用程序本身是.NET MVC)时,统一费率文本框会响应一次。当我将代码移动到JSFiddle以进行此编写时,该框根本不响应。这是可观察的:

self.serviceFeeComputed= ko.computed(function () {
    if (self.ServiceFee.Percentage() !== null 
        && self.ServiceFee.Percentage() !== 0) {
            return self.Amount() * (self.ServiceFee.Percentage() / 100);
    } else {
        return self.ServiceFee.FlatRate();
    }
});

尝试解决方案:过去两周我花了大约6到8个小时试图解决这个问题。以下是我尝试过的一些事情:

  1. 我已经用不同的方式定义了视图模型,例如函数或JavaScript对象:var viewModel = { ... }

  2. 我已将ServiceFee变成了一个可观察的 - 没有结果,所以我改回来了。

  3. 我已将Percentage文本框复制到Flat Rate文本框中,以确保其他属性相同。

  4. 我已从ko.computed()切换到ko.pureComputed()

  5. 我已经切换了条件语句的运行顺序,因此我先检查self.ServiceFee.FlatRate()。这会导致统一费率文本框更新费用,但不会更新百分比。关键这个事实,我做了一个搜索并找到了这个SO question,但是在计算出来的两个observable中,我没有得到一个有效的结果。我还尝试了此解决方案的不同变体,例如使用observable创建变量或将它们添加到一起。无论我做什么,似乎条件语句中检查的第一个变量是接收订阅的变量。

    self.serviceFeeComputed = ko.computed(function () {
        self.ServiceFee.Percentage();
        self.ServiceFee.FlatRate();
        if (self.ServiceFee.Percentage() !== null && self.ServiceFee.Percentage() !== 0) {
            return self.Amount() * (self.ServiceFee.Percentage() / 100);
        } else {
            return self.ServiceFee.FlatRate();
        }
    });
    
  6. 理想分辨率:我希望两个文本框都能更新计算出的观察值,无论用户在百分比和统一费率之间来回切换多少次。

    提前致谢。

1 个答案:

答案 0 :(得分:2)

你的问题来自两件事:

  1. 正如Drummad所有 在他的评论中指出,你过于复杂化了 错误地将jQuery与KO结合起来
  2. 您在确定何时使用百分比以及何时使用扁平化
  3. 时遇到了错误

    我已将代码修改为CodePen

    // You will not need jQuery at all, KO is enough
    // You need a boolean property to determine if the Flatrate or the Percentage is used
    self.ServiceFee = {
      Percentage: ko.observable(),
      FlatRate: ko.observable(),
      IsPercentage: ko.observable(true) // Add this property to ServiceFee
    };
    
    self.serviceFeeComputed = ko.computed(function() {
      //if (self.ServiceFee.Percentage() !== null && self.ServiceFee.Percentage() !== 0) {
      if (self.ServiceFee.IsPercentage()) { // this is the right condition
        return self.Amount() * (self.ServiceFee.Percentage() / 100);
      } else {
        return self.ServiceFee.FlatRate();
      }
    });
    <!-- You will not need jQuery at all, KO is enough -->
    <!-- You need a boolean property to determine if the Flatrate or the Percentage is used -->
    
    <label class="radio-inline col-xs-2 col-xs-offset-1">
      <input name="Test" type="radio" data-bind="checkedValue: true, checked: ServiceFee.IsPercentage" />
      <!-- <input type="radio" name="percentageOrFlatRate" value="percentage" /> -->
    </label>
    ... other code ...
    <input class="form-control"
      data-bind="textInput: ServiceFee.Percentage, valueUpdate: 'afterkeydown', enable: ServiceFee.IsPercentage"
      data-value="percentage" id="ServiceFee_Percentage" name="ServiceFee.Percentage"
      placeholder="0.00" type="number" value="" />
    
    ... other code ...
    
    <label class="radio-inline  col-xs-2 col-xs-offset-1">
      <input name="Test" type="radio" data-bind="checkedValue: false, checked: ServiceFee.IsPercentage" />
      <!-- <input type="radio" name="percentageOrFlatRate" value="flatRate" /> -->
    </label>
    ... other code ...
    <input class="form-control"
      data-bind="textInput: ServiceFee.FlatRate, valueUpdate: 'afterkeydown', disable: ServiceFee.IsPercentage"
      data-value="flatRate" id="ServiceFee_Percentage" name="ServiceFee.Percentage"
      placeholder="0.00" type="number" value="" />