2016-10-10 8 views
2

私は入力フィールドを動的に拡大することを目指しています。入力フィールドに入力を開始するときには、新しい空のフィールドがその下に表示されます。observableを含むobservableArrayを動的に拡大する

私はこのようなことを期待していました。

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

予想通り、現在の実装では機能しません。理由は2つあります。

  • あなたはdocsに応じ$dataコンテキストプロパティに入力フィールドを結合しているが、観察に供給された文字列がある
      $rawDataプロパティにバインドして、実際の観測値にバインドします。
    1. Computed dependency trackingは、評価実行中に検出された各観測値を追加します。明らかに新しい観測値を押すことは依存関係を追加しません。観測可能な配列を単一のオブザーバブルに初期化することは、これに対する解決策になります。これを行うことで、!lenのチェックを削除することもできます。以下は

    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を追加すると、その変更を追跡するためのサブスクリプションが作成されます。空でない値に変更されると、サブスクリプションが破棄され(1回だけ必要です)、ルーチンが繰り返されます。

    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>

  • +0

    これは良い解決策のように思える - が、文字列は、私の例ではバインドされたのではなく、観察可能である理由私はわかりません。あなたは詳細を教えていただけますか? – Shadow

    +0

    私は、現在の実装が期待どおりに機能しなかった理由を詳細に答えを更新し、よりコンパクトなバージョン –

    +1

    '' $ rawData''を私の実装で修正して代替を更新しました。あなたの他のバージョンもより効率的に見えますが、空になったら物を崩壊させることを考えていましたので、今は残しておきます。ありがとうヒープ:) – Shadow

    関連する問題