2015-06-12 65 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