昨天我提出了这个问题: How can I refresh or load JSON to my viewModel on Knockout JS with complex models
修复后一切正常,但是当我尝试使用复杂的 json 在 viewModel 中加载时,某些按钮(特别是在组上)不起作用。
恢复问题。我有一个包含先前序列化数据的 json。我使用该 json 填充 viewModel,这有效,正确加载数据,但问题出在“组”模板中,因为数据已加载但按钮不起作用,唯一起作用的按钮是“删除”团体”。 (请引用图片)
有办法解决这个问题吗?谢谢。
有问题的 Jsfiddle 示例 http://jsfiddle.net/y98dvy56/26/
这是正文 html
<div class="container">
<h1>Knockout.js Query Builder</h1>
<div class="alert alert-info">
<strong>Example Output</strong><br/>
</div>
<div data-bind="with: group">
<div data-bind="template: templateName"></div>
</div>
<input type="submit" value="Save" data-bind="click: Save"/>
</div>
<!-- HTML Template For Conditions -->
<script id="condition-template" type="text/html">
<div class="condition">
<select data-bind="options: fields, value: selectedField"></select>
<select data-bind="options: comparisons, value: selectedComparison"></select>
<input type="text" data-bind="value: value"></input>
<button class="btn btn-danger btn-xs" data-bind="click: $parent.removeChild"><span class="glyphicon glyphicon-minus-sign"></span></button>
</div>
</script>
<!-- HTML Template For Groups -->
<script id="group-template" type="text/html">
<div class="alert alert-warning alert-group">
<select data-bind="options: logicalOperators, value: selectedLogicalOperator"></select>
<button class="btn btn-xs btn-success" data-bind="click: addCondition"><span class="glyphicon glyphicon-plus-sign"></span> Add Condition</button>
<button class="btn btn-xs btn-success" data-bind="click: .addGroup"><span class="glyphicon glyphicon-plus-sign"></span> Add Group</button>
<button class="btn btn-xs btn-danger" data-bind="click: $parent.removeChild"><span class="glyphicon glyphicon-minus-sign"></span> Remove Group</button>
<div class="group-conditions">
<div data-bind="foreach: children">
<div data-bind="template: templateName"></div>
</div>
</div>
</div>
</script>
<!-- js -->
<script src="js/vendor/knockout-2.2.1.js"></script>
<script src="js/vendor/knockout-mapping.js"></script>
<script src="js/condition.js"></script>
<script src="js/group.js"></script>
<script src="js/viewModel.js"></script>
<script>
window.addEventListener('load', function(){
var json =
{"group":{"templateName":"group-template","children":[{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"},{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"},{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"},{"templateName":"group-template","children":[{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"},{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"},{"templateName":"condition-template","fields":["Points","Goals","Assists","Shots","Shot%","PPG","SHG","Penalty Mins"],"selectedField":"Points","comparisons":["=","<>","<","<=",">",">="],"selectedComparison":"=","value":0,"text":"Points = 0"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0)"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0 AND (Points = 0 AND Points = 0 AND Points = 0))"},"text":"(Points = 0 AND Points = 0 AND Points = 0 AND (Points = 0 AND Points = 0 AND Points = 0))"};
var vm = new QueryBuilder.ViewModel();
ko.mapping.fromJS(json.group, {}, vm.group);
ko.applyBindings(vm);
}, true);
</script>
条件.js:
window.QueryBuilder = (function(exports, ko){
function Condition(){
var self = this;
self.templateName = 'condition-template';
self.fields = ko.observableArray(['Points', 'Goals', 'Assists', 'Shots', 'Shot%', 'PPG', 'SHG', 'Penalty Mins']);
self.selectedField = ko.observable('Points');
self.comparisons = ko.observableArray(['=', '<>', '<', '<=', '>', '>=']);
self.selectedComparison = ko.observable('=');
self.value = ko.observable(0);
}
exports.Condition = Condition;
return exports;
})(window.QueryBuilder || {}, window.ko);
Group.js
window.QueryBuilder = (function(exports, ko){
var Condition = exports.Condition;
function Group(){
var self = this;
self.templateName = 'group-template';
self.children = ko.observableArray();
self.logicalOperators = ko.observableArray(['AND', 'OR']);
self.selectedLogicalOperator = ko.observable('AND');
// give the group a single default condition
self.children.push(new Condition());
self.addCondition = function(){
self.children.push(new Condition());
};
self.addGroup = function(){
self.children.push(new Group());
};
self.removeChild = function(child){
self.children.remove(child);
};
}
exports.Group = Group;
return exports;
})(window.QueryBuilder || {}, window.ko);
ViewModel.js
window.QueryBuilder = (function(exports, ko){
var Group = exports.Group;
function ViewModel() {
var self = this;
self.group = ko.observable(new Group());
self.load = function (data) {
ko.mapping.fromJS(data, self);
}
self.Save = function () {
console.log(ko.toJSON(self));
}
}
exports.ViewModel = ViewModel;
return exports;
})(window.QueryBuilder || {}, window.ko);
最佳答案
您的问题是由于映射插件使您的数据可观察,但不会使用模型中的功能(例如添加、删除等功能)来扩充您的数据。如果您在将 json 数据插入 View 模型时对其进行控制台日志,您会注意到数据是可观察的,但缺少函数。您需要提供一个映射来自定义您的组、条件等构造函数。因为您的情况下的子数组是混合类型(条件或组),所以这是一个自定义映射来处理这个问题:
var childrenMapping = {
'children': {
create: function(options) {
var data = options.data;
console.log(data);
var object;
switch(data.templateName) {
case 'condition-template':
object = new QueryBuilder.Condition(data);
break;
case 'group-template':
object = new QueryBuilder.Group(data);
break;
}
return object;
}
}
};
然后您只需在初始映射中提供此映射
ko.mapping.fromJS(json.group, childrenMapping, vm.group);
然后在 Group 对象的构造函数中:
function Group(data){
var self = this;
self.templateName = 'group-template';
...
ko.mapping.fromJS(data, childrenMapping, this);
}
您还需要更新 Condition 构造函数以接受映射提供的数据,但由于条件没有子项,因此您无需在此处提供 ChildrenMapping:
function Condition(data){
var self = this;
self.templateName = 'condition-template';
...
ko.mapping.fromJS(data, {}, this);
}
我在两个函数的末尾都有映射,以便映射的值覆盖您的初始值。
这里更新了 jsfiddle:
http://jsfiddle.net/omerio/y98dvy56/32/
这个答案是相关的: knockout recursive mapping issue
关于javascript - 绑定(bind)不适用于 KnockoutJS 中 JSON 加载的嵌套模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30813208/