将嵌套的淘汰视图模型解析为JSON时出现问题

Troubles with parsing nested knockout viewmodels to JSON

本文关键字:JSON 问题 嵌套 淘汰 视图 模型      更新时间:2023-09-26

问题

当我在工作和探索knockoutjs时,我在某个时候陷入了困境。我想将视图模型(以及底层视图模型(序列化为JSON。这将以无限循环结束,因为子视图模型具有引用父视图模型的属性。解决这个问题的最佳实践是什么?

代码

var Partner = function (parent) {
    var self = this;
    self.parent = parent;
    self.name = ko.observable('');
}
var ProjectViewModel = function () {
    var self = this;
    self.nr = ko.observable(0);
    self.tite = ko.observable('');
    self.partners = ko.observableArray();            
    self.addPartner = function () { self.partners.push(new Partner(self)) };
    self.removePartner = function (c) { self.partners.remove(c) };
};
var vm = new ProjectViewModel();
ko.applyBindings(vm);

$("#button").click(function () {
    alert(ko.toJSON(vm));
}

到目前为止我尝试了什么

我尝试在Partner视图模型中添加以下方法:

Partner.prototype.toJSON = function () {
            var copy = ko.toJS(self);
            delete copy.parent;
            return copy;
        }

这只适用于一个合作伙伴,如果ProjectViewModel有多个合作伙伴时,每个合作伙伴的价值都将与上一个伙伴相同。只有当我想将它序列化为JSON时,才会发生这种情况。

有几种方法可以处理这种情况。KO的ko.toJS部分可以正确处理此问题。最终是JSON.stringify(在ko.toJSON中的ko.toJS之后调用(导致错误。

原型上的toJSON方法非常接近,只是您希望处理this而不是self

所以,它看起来像:

Partner.prototype.toJSON = function() {
  var copy = ko.toJS(this);
  delete copy.parent;
  return copy; 
};

其他处理方法:

1-实际上不要将父对象存储在子对象上,只需根据传递给构造函数的参数在任何处理程序中直接引用它。

var Partner = function (parent) {
    var self = this;
    self.name = ko.observable(name);
    self.doSomething = function() {
        //can use "parent" directly here without storing it anywhere
    };
};

2-"隐藏"你的父母参考

var Partner = function (parent) {
    var self = this;
    self.meta = function() {};
    self.meta.parent = parent;
    self.name = ko.observable(name);    
};

您可以将parent值放在函数后面(可以作为可观察对象的子属性(。当你的结构被ko.toJS变成一个普通的JS对象时,函数的任何子属性都会丢失。

3-根据你想做的事情改变你的应用程序的结构。假设每当孩子的名字被更改时,父母都想做出反应。您可以传入回调,设置订阅,并在它更改时执行它

var Partner = function (nameChangedCallback) {
    var self = this;
    self.name = ko.observable(name);    
    if (typeof nameChangedCallback == "function") {
        self.name.subscribe(function() {
           nameChangedCallback.call(self, self);
        });
    }
};