2011-09-08 10 views
4

knockoutjsを使用して動的クエリエディタをコーディングしていますが、ko.toJSONはデータバインドされたフォーム要素によって変更されるまでフィールドを出力しません。次のビューでthis jsfiddleを参照してください:ko.toJSONはフィールドを無視しているようです

<span data-bind="template: {name: 'filterGroupTemplate', data: viewModel}"></span> 

<script type="text/x-jquery-tmpl" id="filterGroupTemplate"> 
    <div class="filterGroup"> 
     <div class="filterGroupParams"> 
      Match 
      <select name="join" data-bind="value: join, options: joins"></select> 
      of the following rules: 
      <button class="addFilter" data-bind="click: addFilter">+</button> 
      <button class="addGroup" data-bind="click: addGroup">{...}</button> 
      <button class="removeGroup">x</button> 
     </div> 
     <span data-bind='template: {name: "filterTemplate", foreach: filters }'></span> 
    </div> 
</script> 

<script type="text/x-jquery-tmpl" id="filterTemplate"> 
    <div class="filter"> 
     {{if $data.filters }}  
      <div data-bind='template: "filterGroupTemplate"'> 
      </div>     
     {{else}} 
      <select data-bind="value: field, options: fields"></select>  
      <select data-bind="value: modifier, options: modifiers"></select> 
      <input type="text" data-bind="value: criteria" /> 
      <button>x</button> 
     {{/if}} 
    </div> 
</script> 

<h2>ViewModel JSON</h2> 
<div data-bind="text: dev()"></div> 

そして、このコード:

// filter class 
var Filter = function() { 
    this.field = ko.observable(); 
    this.modifier = ko.observable(); 
    this.criteria = ko.observable(); 
}; 

// filter group class 
var FilterGroup = function() { 
    // Include a blank filter in every group 
    this.join = ko.observable('All'); 
    this.filters = ko.observableArray([new Filter()]); 
    this.addFilter = function() { 
     var filter = new Filter(); 
     this.filters().push(filter); 
     this.filters.valueHasMutated(); 
    }; 
    this.addGroup = function() { 
     var group = new FilterGroup(); 
     this.filters().push(group); 
     this.filters.valueHasMutated(); 
    }; 
}; 

// Data 
var joins = ['All', 'Any']; 
var modifiers = [ 
    'equals', 
    'not equal to', 
    'less than', 
    'greater than', 
    'contains', 
    'does not contain', 
    'starts with' 
]; 
var fields = ['f1','f2','f3']; 

var viewModel = new FilterGroup(); 
function dev(){ 
    return ko.toJSON(viewModel); 
} 

ko.applyBindings(viewModel); 

ビューモデルは明らかに(このような性質の参加など)の分野事前に初期化がありますが、彼らは現れていませんユーザーがUIでJSONオブジェクトを変更するまで

誰かが私が間違っていることとその修正方法を説明してもらえますか?これは実際にknockoutjs自体のバグのようです。それには、値がない場合はクエリを構築するときにデフォルトを使用しますが、これは駄目な解決策のように思われます

答えて

8

あなたのコードには微妙な問題があり、彼らの髪を引き裂く。選択要素のvalueバインディングでoptionsバインディングを使用する場合は、の前にoptionsを指定する必要があります。

バインディングは利用可能なオプションを構築し、次に値バインディングは選択されたオプションとビューモデルの値が同期するように強制します。それらの順序が間違っていると、valueバインディングが最初に実行され、一致するオプションが選択されていないことがわかるため、値をnullに設定します。

はここ順序であなたのフィドルが切り替わる:http://jsfiddle.net/rniemeyer/32fYk/

これはgithubの時代のカップルに記録された、最近ここに:https://github.com/SteveSanderson/knockout/issues/58。現在のところ、バインディングが同じデータバインドの別のバインディングの前に実行されることを強制する簡単な方法はありません。うまくいけば、ある時点でこれが対処されるだろう。私は、他のものがリストされているかどうかを2つのバインディングでチェックすることで、このケースを特に処理する修正を考えることができます。

+1

ありがとうございました!これは美しく動作します。私の唯一の問題は、依然として入力要素の制約データバインドに問題があるように見えますが、空白の入力値が決して存在しないため、これは自明です。今アイテムを削除するための機能を追加する... あなたのブログは、私のGoogle検索の大部分が主導した場所です - 私はここ数時間、ほとんどすべてを読んで過ごしました。 – daedalus28

+4

JSONにシリアル化するとき、値がnullのプロパティは無視されます。したがって、Filter( 'this.criteria = ko.observable( ''))のコンストラクタ関数で空の文字列に' criteria'を強制することによって入力要素を修正できます。 ; ') –

+1

ありがとう、それも同様に働いた:) – daedalus28

関連する問題