动态增长包含可观察量的observableArray

时间:2016-10-10 00:23:32

标签: javascript html knockout.js

我的目标是拥有一个动态增长的输入字段列表 - 每当我开始在输入字段中输入时,它下面都会出现一个新的空字符。

我期待这样的事情发挥作用;

function Model() {
    // Build a basic observable array
    this.inputs = ko.observableArray();

    // Whenever this changes, or on initial creation of this computed
    // add a new empty field if the last one has any text in it.
    ko.computed(function () {
        var len = this.inputs().length;
        // If there are no fields (initial run) or the last element is falsey...
        if (!len || this.inputs()[len-1]()) {
            // Create a new observable and add it to the array.
            this.inputs.push(ko.observable(""));
        }
    }, this);
}

下面是一些将模型绑定到的基本HTML;

<ul data-bind="foreach: inputs">
    <li><input data-bind="textInput: $data" /></li>
</ul>

当我输入正确显示的文本框(显示此函数在创建时运行)时,不会调用计算。

那么我必须做些什么来让计算机正确地重新评估?有没有更好的方法来实现一个实际上在淘汰赛中有效的动态增长列表?

这里是jsfiddle我在这里的确切代码,以帮助调试此问题。

1 个答案:

答案 0 :(得分:1)

当前实现无法按预期运行有两个原因:

  1. 您将输入字段绑定到$data context属性,根据docs,该属性是提供给observable的字符串。绑定到$rawData属性以绑定到实际的observable。
  2. Computed dependency tracking添加在任何评估运行期间遇到的每个可观察对象。推动新的可观察量显然不会增加依赖性。将可观察数组初始化为单个observable将是一个解决方案。通过执行此操作,还可以删除!len检查。
  3. function Model() {
      this.inputs = ko.observableArray([ko.observable("")]);
    
      ko.computed(function() {
        if (!!this.inputs()[this.inputs().length - 1]()) {
          this.inputs.push(ko.observable(""));
        }
      }, this);
    }
    
    ko.applyBindings(new Model());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <ul data-bind="foreach: inputs">
      <li>
        <input data-bind="textInput: $rawData" />
      </li>
    </ul>

    以下是另一种例行程序。它递归地添加了一个observable。添加observable时,会创建订阅以跟踪其更改。当它变为非空值时,处理订阅(只需要一次)并重复例程。

    function Model() {
      this.inputs = ko.observableArray();
    
      this.addItem = function() {
        var newItem = ko.observable("");
        this.inputs.push(newItem);
        var sub = newItem.subscribe(function(newValue) {
          if (!!newValue) {
            sub.dispose();
            this.addItem();
          }
        }, this);
      }
    
      this.addItem();
    }
    ko.applyBindings(new Model());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <ul data-bind="foreach: inputs">
      <li>
        <input data-bind="textInput: $rawData" />
      </li>
    </ul>