如何在带有复杂模型的Knockout JS上刷新JSON或将JSON加载到我的viewModel [英] How can I refresh or load JSON to my viewModel on Knockout JS with complex models

查看:140
本文介绍了如何在带有复杂模型的Knockout JS上刷新JSON或将JSON加载到我的viewModel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从这里派生代码: http://kindohm.github.io/knockout-query-builder/

该代码在客户端运行良好. 但是,当我尝试将viewModel另存为JSON,然后从服务器检索数据时,UI根本不会刷新.

这是原始的viewModel:

window.QueryBuilder = (function(exports, ko){

  var Group = exports.Group;

  function ViewModel() {
    var self = this;
    self.group = ko.observable(new Group());

        // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.group().text();
    });
  }

  exports.ViewModel = ViewModel;
  return exports;

})(window.QueryBuilder || {}, window.ko);

我将下一个方法添加到viewModel

self.Save = function () {
    console.log(ko.toJSON(self));
}

将此按钮添加到视图

<input type="submit" value="Save" data-bind="click: Save"/>

这是组viewModel:

window.QueryBuilder = (function(exports, ko){

  var Condition = exports.Condition;

  function Group(data){
    var self = this;

    self.templateName = data.templateName;
    self.children = ko.observableArray(data.children);
    self.logicalOperators = ko.observableArray(data.logicalOperators);
    self.selectedLogicalOperator = ko.observable(data.selectedLogicalOperator);

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

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      var result = '(';      
      var op = '';
      for (var i = 0; i < self.children().length; i++){
        var child = self.children()[i];
        console.log(child);
        result += op + child.text();
        op = ' ' + self.selectedLogicalOperator() + ' ';
      }
      return result += ')';
    });
  }

  exports.Group = Group;
  return exports;

})(window.QueryBuilder || {}, window.ko);

因此,当我按下保存"按钮时,控制台将显示此viewModel的JSON,此处一切正常.

这是返回的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"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0)"},"text":"(Points = 0 AND Points = 0 AND Points = 0)"}

我做了一个简单的技巧来避免与服务器的连接,所以我将json复制并粘贴到load事件上,然后发送给viewModel的构造函数:

  var vm;
  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"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0)"},"text":"(Points = 0 AND Points = 0 AND Points = 0)"}; 

    vm = new QueryBuilder.ViewModel(json);  
    ko.applyBindings(vm);           
  }, true);

然后我修改viewModel以接收json参数

window.QueryBuilder = (function(exports, ko){

  var Group = exports.Group;

  function ViewModel(json) {
    var self = this;
    self.group = ko.observable(json.group);

        // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.group().text();
    });
    self.Save = function () {
        console.log(ko.toJSON(self));
    }   
  }

  exports.ViewModel = ViewModel;
  return exports;

})(window.QueryBuilder || {}, window.ko);

刷新index.html时,视图永远不会正确加载,并在JS控制台上显示此错误:

TypeError: self.group(...).text is not a function
return self.group().text();

有人知道我的错误在哪里?


我遇到的最后一个问题与孩子的text()函数有关. 我通过使用try/catch来解决此问题.因此,当viewModel是新的时,它具有text()函数,但是当加载时,text()不存在,因此我直接从文本"字段中获取值.

try {
    result += op + child.text();
}
catch(err) {
    result += op + child.text;
}           

问题出在组"类和条件"类上. 这是当前有效的代码:

window.QueryBuilder = (function(exports, ko){

  var Condition = exports.Condition;

  function Group(data){
    var self = this;

    self.templateName = data.templateName;
    self.children = ko.observableArray(data.children);
    self.logicalOperators = ko.observableArray(data.logicalOperators);
    self.selectedLogicalOperator = ko.observable(data.selectedLogicalOperator);

    // give the group a single default condition
    self.children.push(new Condition(data.children[0]));

    self.addCondition = function(){
        self.children.push(new Condition());
    };

    self.addGroup = function(){
        self.children.push(new Group());
    };

    self.removeChild = function(child){
        self.children.remove(child);
    };

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      var result = '(';      
      var op = '';
      for (var i = 0; i < self.children().length; i++){
        var child = self.children()[i];

        try {
            result += op + child.text();
        }
        catch(err) {
            result += op + child.text;
        }           

        op = ' ' + self.selectedLogicalOperator() + ' ';
      }
      return result += ')';
    });
  }

  exports.Group = Group;
  return exports;

})(window.QueryBuilder || {}, window.ko);

window.QueryBuilder = (function(exports, ko){

  function Condition(data){
    var self = this;

    self.templateName = data.templateName;

    self.fields = ko.observableArray(data.fields);
    self.selectedField = ko.observable(data.selectedField);

    self.comparisons = ko.observableArray(data.comparisons);

    self.selectedComparison = ko.observable(data.selectedComparison);

    self.value = ko.observable(data.value);

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.selectedField() + 
        ' ' +
        self.selectedComparison() + 
        ' ' + 
        self.value();
    });
  }

  exports.Condition = Condition;
  return exports;

})(window.QueryBuilder || {}, window.ko);

解决方案

您应该采用与加载self.group = ko.observable(new Group());时类似的方法,而不是self.group = ko.observable(json.group);,但这一次在json.group数据>

 self.group = ko.observable(new Group(json.group));

我看不到Group的定义位置,但是您应该确保它能够处理并将现在传递的JSON转换为可观察对象.

I fork the code from here: http://kindohm.github.io/knockout-query-builder/

The code works nice on the client side. But when I try to save the viewModel as JSON and then retrieve the data from the server the UI never refresh at all.

This is the original viewModel:

window.QueryBuilder = (function(exports, ko){

  var Group = exports.Group;

  function ViewModel() {
    var self = this;
    self.group = ko.observable(new Group());

        // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.group().text();
    });
  }

  exports.ViewModel = ViewModel;
  return exports;

})(window.QueryBuilder || {}, window.ko);

I be added the next method to the viewModel

self.Save = function () {
    console.log(ko.toJSON(self));
}

Added this button to the view

<input type="submit" value="Save" data-bind="click: Save"/>

This is the Group viewModel:

window.QueryBuilder = (function(exports, ko){

  var Condition = exports.Condition;

  function Group(data){
    var self = this;

    self.templateName = data.templateName;
    self.children = ko.observableArray(data.children);
    self.logicalOperators = ko.observableArray(data.logicalOperators);
    self.selectedLogicalOperator = ko.observable(data.selectedLogicalOperator);

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

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      var result = '(';      
      var op = '';
      for (var i = 0; i < self.children().length; i++){
        var child = self.children()[i];
        console.log(child);
        result += op + child.text();
        op = ' ' + self.selectedLogicalOperator() + ' ';
      }
      return result += ')';
    });
  }

  exports.Group = Group;
  return exports;

})(window.QueryBuilder || {}, window.ko);

So when I press the "save" button the console show the JSON from this viewModel, everything fine here.

This is the JSON returned:

{"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"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0)"},"text":"(Points = 0 AND Points = 0 AND Points = 0)"}

I make a simple hack to avoid the connection to the server, so I take that json copy and paste on the load event and send to the constructor of the viewModel:

  var vm;
  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"}],"logicalOperators":["AND","OR"],"selectedLogicalOperator":"AND","text":"(Points = 0 AND Points = 0 AND Points = 0)"},"text":"(Points = 0 AND Points = 0 AND Points = 0)"}; 

    vm = new QueryBuilder.ViewModel(json);  
    ko.applyBindings(vm);           
  }, true);

Then I modify the viewModel to recibe the json parameter

window.QueryBuilder = (function(exports, ko){

  var Group = exports.Group;

  function ViewModel(json) {
    var self = this;
    self.group = ko.observable(json.group);

        // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.group().text();
    });
    self.Save = function () {
        console.log(ko.toJSON(self));
    }   
  }

  exports.ViewModel = ViewModel;
  return exports;

})(window.QueryBuilder || {}, window.ko);

When I refresh the index.html the view is never loaded correctly and show this error on the JS console:

TypeError: self.group(...).text is not a function
return self.group().text();

Someone knows where is my mistake?


The last problem I had was related to the text() function on the child. I fix this with the use of try/catch. So when the viewModel are new it have the text() function, but when this is loadad the text() does not exist, so I take the value directly from the "text" field.

try {
    result += op + child.text();
}
catch(err) {
    result += op + child.text;
}           

The problem was on the Group class and Condition class. This is the current and working code:

window.QueryBuilder = (function(exports, ko){

  var Condition = exports.Condition;

  function Group(data){
    var self = this;

    self.templateName = data.templateName;
    self.children = ko.observableArray(data.children);
    self.logicalOperators = ko.observableArray(data.logicalOperators);
    self.selectedLogicalOperator = ko.observable(data.selectedLogicalOperator);

    // give the group a single default condition
    self.children.push(new Condition(data.children[0]));

    self.addCondition = function(){
        self.children.push(new Condition());
    };

    self.addGroup = function(){
        self.children.push(new Group());
    };

    self.removeChild = function(child){
        self.children.remove(child);
    };

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      var result = '(';      
      var op = '';
      for (var i = 0; i < self.children().length; i++){
        var child = self.children()[i];

        try {
            result += op + child.text();
        }
        catch(err) {
            result += op + child.text;
        }           

        op = ' ' + self.selectedLogicalOperator() + ' ';
      }
      return result += ')';
    });
  }

  exports.Group = Group;
  return exports;

})(window.QueryBuilder || {}, window.ko);

window.QueryBuilder = (function(exports, ko){

  function Condition(data){
    var self = this;

    self.templateName = data.templateName;

    self.fields = ko.observableArray(data.fields);
    self.selectedField = ko.observable(data.selectedField);

    self.comparisons = ko.observableArray(data.comparisons);

    self.selectedComparison = ko.observable(data.selectedComparison);

    self.value = ko.observable(data.value);

    // the text() function is just an example to show output
    self.text = ko.computed(function(){
      return self.selectedField() + 
        ' ' +
        self.selectedComparison() + 
        ' ' + 
        self.value();
    });
  }

  exports.Condition = Condition;
  return exports;

})(window.QueryBuilder || {}, window.ko);

解决方案

Instead of self.group = ko.observable(json.group);, you should take a similar approach as you did on load self.group = ko.observable(new Group());, but this time pass the json.group data in Group

 self.group = ko.observable(new Group(json.group));

I don't see where Group is defined, but you should make sure that it is able to handle and convert the JSON you now pass in, into observables.

这篇关于如何在带有复杂模型的Knockout JS上刷新JSON或将JSON加载到我的viewModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆