如果值在外部更改,则无法检测到Knockout可观察到的更改

rom*_*n m 2 observable knockout.js

我有一个绑定到的文本框列表ko.observableArray.

我必须确保文本框值不能为空,并且我通过将值设置为0来实现,如果它是空白的 blur()

问题是使用jQuery完成的值更改未通过knockout注册.

如何观察模型中的值变化?

看看我简化的小提琴,以了解重点 - http://jsfiddle.net/k45gd/1/

HTML

<input type="number" data-bind="value: age" />
<span data-bind="text: age"></span>
<button data-bind="click: setAgeExternally">I want the label to change to 0</button>
Run Code Online (Sandbox Code Playgroud)

JS

var model = function() {
    this.age = ko.observable(21);

    //this code is outside of the model, this is oversimplification
    this.setAgeExternally = function(){
        $('input').val(0);
    }
};

ko.applyBindings(new model());
Run Code Online (Sandbox Code Playgroud)

Mic*_*est 14

你需要两件事:

  1. 使用jQuery更改元素的值后,您需要让Knockout知道更新模型.您可以通过触发change事件来完成此操作:

    $('input').val(0).trigger('change');
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于Knockout(在3.1.0之前)响应jQuery事件,它需要知道你正在使用jQuery.为此,您必须在Knockout之前在文档中包含jQuery.

这是两个更新的小提琴:http://jsfiddle.net/mbest/k45gd/2/


Cod*_*hug 5

在您提供的示例中,您将使用以下代码更新输入框:

this.setAgeExternally = function(){
    $('input').val(0);
}
Run Code Online (Sandbox Code Playgroud)

考虑到输入绑定到age属性,这样做会更简单:

this.setAgeExternally = function(){
  this.age(0);
}
Run Code Online (Sandbox Code Playgroud)

但是,即使这不是真的需要,因为age属性在您的viewmodel上公开.所以外部代码可以这样做,并且实际上并不需要setAgeExternally方法:

model.age(0);
Run Code Online (Sandbox Code Playgroud)

让我们回到你原来的问题 - 你描述但不发布代码的问题.您提到您有一个绑定到可观察数组的输入框列表.

使用可观察数组时,您需要注意一个有趣的问题:

http://knockoutjs.com/documentation/observableArrays.html上的文档:

关键点:observableArray跟踪数组中的对象,而不是这些对象的状态

简单地将对象放入observableArray并不会使该对象的所有属性本身都可观察到.当然,如果您愿意,您可以观察这些属性,但这是一个独立的选择.observableArray只跟踪它所拥有的对象,并在添加或删除对象时通知侦听器.

根据您列出的要求,根本不需要jQuery.您可以尝试以下三部分解决方案:

  1. 使您的observableArray包含observable.所以你最终得到的结果如下:

    var model = function() {
      this.ages = ko.observableArray([
        {age: ko.observable(13)},
        {age: ko.observable(18)},
        {age: ko.observable(16)},
        {age: ko.observable(13)}
      ]);
    };
    
    Run Code Online (Sandbox Code Playgroud)
  2. 接下来,创建一个敲除扩展器,如果空白则自动重置为0

    ko.extenders.defaultIfBlank = function(target, defaultValue) {
      var result = ko.computed({
        read: target,  //always return the original observables value
        write: function(newValue) {
            if (newValue == "") {
              target(defaultValue);
            } else {
               target(newValue);
            }
        }
      });
    
      //initialize with current value to make sure it is not blank
      result(target());
    
      //return the new computed observable
      return result;
    };
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将扩展器应用于阵列中的observable

    var model = function() {
      this.ages = ko.observableArray([
        ko.observable(13).extend({defaultIfBlank: "0"}),
        ko.observable(18).extend({defaultIfBlank: "0"}),
        ko.observable(16).extend({defaultIfBlank: "0"}),
        ko.observable(13).extend({defaultIfBlank: "0"})
      ]);
    };
    
    Run Code Online (Sandbox Code Playgroud)

工作小提琴:http://jsfiddle.net/tlarson/GF3Xe/