2011-09-08 157 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本身的bug。如果涉及到它,如果值不存在,我將在構建查詢時使用默認值,但這似乎是一個蹩腳的解決方案

回答

8

您的代碼中存在一個微妙的問題,導致許多人撕掉他們的頭髮。當您在select元素上使用options綁定與value綁定時,您需要在value之前指定options

options綁定會構建可用選項,然後值綁定會強制所選選項和視圖模型值同步。如果按錯誤順序排列它們,則value綁定首先運行,並且看到沒有匹配的選項可供選擇,因此它將該值設置爲null。

這裏是秩序的提琴切換:http://jsfiddle.net/rniemeyer/32fYk/

這已被記錄在GitHub上了幾次,最近一次是在這裏:https://github.com/SteveSanderson/knockout/issues/58。目前還沒有一種簡單的方法來強制綁定在同一個數據綁定中的另一個綁定之前運行。希望在某些時候這將得到解決。我可以通過讓兩個綁定檢查是否列出另一個綁定來解決這個問題。

+1

非常感謝!這工作很好。我唯一的問題是,這個問題似乎仍然適用於輸入元素上的約束數據綁定,但這很重要,因爲不應該有空白的輸入值。現在添加刪除項目的功能... 爲了記錄,您的博客是我的谷歌搜索的主要來源 - 我花了幾個小時閱讀幾乎所有的東西。 – daedalus28

+4

當序列化爲JSON時,值爲null的屬性將被忽略,因此您可以通過將'criteria'強制爲Filter的構造函數中的空字符串來更正您的輸入元素('this.criteria = ko.observable('') ;') –

+1

謝謝,那也工作得很好:) – daedalus28