I am coding a dynamic query editor with knockoutjs, but ko.toJSON is not outputting the fields until they have been modified by a data-bound form element. See this jsfiddle with the following view:
<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>
And this code:
// 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);
Though the view model clearly has fields pre-initialized (such as the join property), they're not showing up in the JSON object until the user changes them in the UI.
Can someone please explain what I'm doing wrong and how to fix it? This actually seems like a bug with knockoutjs itself. If it comes down to it, I'll just use defaults when building the query if the values aren't there, but this seems like a crappy solution