【问题标题】:Knockout - Can't update Observable value using Subscribe (due to extension validation)淘汰赛 - 无法使用订阅更新 Observable 值(由于扩展验证)
【发布时间】:2013-04-14 12:58:50
【问题描述】:

我已尝试实施以下建议,但每次更新值时似乎都没有触发所需的反应。这可能是由于我是 Knockout 的新手,所以我的实施。

我有一个绑定到 TextBoxFor 的 observable (Amount)。

@Html.TextBoxFor(m => m.Amount, new { type = "number", data_bind = "value: Amount" })

当输入一个值时,需要对其进行验证以确保它不超过 999999。除此之外,如果该值小于 50,则需要将其设置为 50。这些检查需要在每个“金额”更改的时间。

var viewModel = {
    Amount: ko.observable().extend({numeric: 0, max: 999999})
};

我已尝试实施解决方案(在我之前帖子的答案中),但我无法让这些解决方案发挥作用。

我想出的最好方法是创建一个计算如下。这将检查输入值并在第一次尝试时正确更新。随后的值更改不会触发屏幕上的更改,但单步执行代码似乎会更新 ViewModel.Amount 值。

@Html.TextBoxFor(m => m.Amount, new { type = "number", data_bind = "value: amountMin" })


quoteVehicleViewModel.VehicleMileage = ko.observable(0);


viewModel.amountMin = ko.computed({
    read: function () {
        return viewModel.Amount();  
    },
    write: function (value) {
        if (value < 50) {
            viewModel.Amount(50);
        }
    }
}).extend({ numeric: 0, max: 999999 });

** 在控制台中输入的“viewModel.Amount()”显示值为 1000,但屏幕上的值仍显示为输入的值。

感谢您的帮助

约翰

【问题讨论】:

  • 非常感谢您的回复 Joseph - 我已经看到您的 JSFiddle 工作了。我已经尝试在我的解决方案中实现,虽然我可以看到 coerceMin 函数在页面加载时运行,但当我更改文本框中的值时它不会被命中。除了您在下面添加的代码之外,是否还有其他密钥(来自您的 JSFiddle)需要执行此操作?
  • 有一条偷偷摸摸的行 ko.validation.registerExtenders(); 我没有在答案中放入实际的扩展器 sn-p 。您是否将这一行包含在您的代码中?
  • 你好。是的,我已经包含了 registerExtenders 并且 coerceMin 代码在页面加载时触发,而不是在输入值时触发。谢谢

标签: knockout.js knockout-2.0 knockout-validation


【解决方案1】:

非常相似的问题在这里: Make Knockout applyBindings to treat select options as number

尽管订阅,您仍可以计算出价值。 它看起来像:

var viewModel = {
    _amount: ko.observable(100).extend({numeric: 0, max: 999999, reset: true}),
    Amount : ko.computed(function(){
       return _amount < 50 ? 50 : _amount;
   })
};


ko.applyBindings(viewModel);

编辑

我还查看了您在此处使用的扩展程序。 您可以添加到您的扩展器最小值并将其传递给您的 observable 参数。 您显然必须在扩展器的 write 方法中编写一些代码

类似:

ko.extenders.numeric = function(target, min) {
...
   write:function(v){
      ...
      if(v<50) v=50;
      ...
      target(v)


   }
...
}

【讨论】:

  • 您好,SiMet,感谢您的回复。我还有几个问题............在你的第一个例子中,使用计算而不是订阅,你将你的值绑定到哪个值?例如 。我尝试了 _amount 和 Amount 但未触发计算。有没有办法实现特定于可观察的扩展器解决方案?我是 KO 新手,但看起来 ko.extenders.numeric 会影响所有可观察对象?谢谢
【解决方案2】:

据我所知,淘汰赛验证不提供任何直接从规则定义访问 observable 的能力。如果可能的话,您可以在自定义验证规则中强制该值。

我发现的最佳替代方法是为您要强制执行的每个规则创建一个自定义扩展程序。

以下是“min”规则的强制扩展示例:

  ko.extenders.coerceMin = function (target, enable) {
      //collect rule values
      var minRule = ko.utils.arrayFirst(target.rules(), function (val) {
          return val.rule === "min"
      });
      if (minRule === null) {
          throw Error("coerceMin extender must be used in conjunction with the 'min' knockout validation rule");
      }
      var minValue = minRule.params;
      //listen for changes and coerce when necessary
      var subscription = null;
      if (enable && !subscription) {
          subscription = target.subscribe(function (newValue) {
              if (!isNaN(newValue)) {
                  var newValueAsNum = parseFloat(+newValue);
                  var valueToWrite = newValueAsNum < minValue ? minValue : newValueAsNum;
                  //only write if it changed
                  if (valueToWrite !== newValue) {
                      target(valueToWrite);
                  }
              }
          });
      } else {
          if (subscription) {
              subscription.dispose();
          }
      }

      //return the original observable
      return target;
  };

您可以像这样在视图模型中应用它:

var viewModel = {
    Amount: ko.observable()
              .extend({numeric: 0, min: 50, max: 999999})
              .extend({coerceMin: true});
};

这里有一个小提琴来演示:http://jsfiddle.net/f2rTR/1/

【讨论】:

    猜你喜欢
    • 2019-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-20
    • 2018-06-05
    • 2016-04-19
    • 2016-02-29
    相关资源
    最近更新 更多