2015-06-12 121 views
0

昨天我提出这样一个问题: How can I refresh or load JSON to my viewModel on Knockout JS with complex models绑定不通过JSON在KnockoutJS加载嵌套模板工作

一切工作与修复好,但是当我尝试使用一个复杂的JSON在视图模型加载一些的这些按钮(特别是在组上)不起作用。

恢复问题。我有一个与以前的序列化数据的JSON。我使用该json来填充viewModel,这个工作,正确加载数据,但问题出现在“组”模板中,因为数据已加载,但按钮不起作用,唯一正在工作的按钮是“删除组”。 (请参考图片)

任何想法解决这个问题?谢谢。

的问题 http://jsfiddle.net/y98dvy56/26/

的jsfiddle例子! Check this picture. The red circles indicates the buttons with problems. The green circles indicates the buttons without problems.

这里是正文的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> 

Condition.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); 
+0

您能提供的jsfiddle与您的代码? – omerio

+0

@omerio是的,这是jsfiddle代码。 http://jsfiddle.net/y98dvy56/26/ – HolloW

+1

你的问题是由映射插件使你的数据可观察的事实造成的,但不会添加添加,删除等...函数。如果您在将json数据插入视图模型时执行控制台日志记录,则会注意到数据是可观察的,但功能缺失。你需要提供一个映射来定制你的组,条件等..构造函数,这里解释http://knockoutjs.com/documentation/plugins-mapping.html – omerio

回答

2

您的问题是由映射插件使您的数据可观察的事实造成的,但不会使用模型中的函数(例如添加,删除等...函数)来增强数据。如果您在将json数据插入视图模型时执行控制台日志记录,则会注意到数据是可观察的,但功能缺失。你需要提供一个映射来定制你的组,条件等。构造函数。因为在你的情况下,孩子阵列是混合型(条件或一组)的下面是一个自定义映射关系采取照顾:

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); 

则该组对象的构造函数中:

function Group(data){ 

    var self = this; 

    self.templateName = 'group-template'; 
    ... 

    ko.mapping.fromJS(data, childrenMapping, this);  
} 

您还需要更新条件的构造函数接受由映射提供的数据,但由于条件没有孩子,你不需要在这里提供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

+0

感谢您的时间。我对映射非常接近,唯一的区别(并且在我的代码中缺少)是模板名称的切换。 – HolloW