当我在工作和探索knockoutjs时,我陷入了困境。我想将一个viewmodel(和底层的viewmodels)序列化为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 viewmodel中添加以下方法:
Partner.prototype.toJSON = function () {
var copy = ko.toJS(self);
delete copy.parent;
return copy;
}
这仅适用于一个合作伙伴,如果ProjectViewModel具有多个合作伙伴,则每个合作伙伴将具有与最后一个合作伙伴相同的值。仅当我想将其序列化为JSON时才会发生这种情况。
答案 0 :(得分:2)
有几种方法可以解决这种情况。 KO的ko.toJS
部分正确处理此问题。它最终是JSON.stringify
(在ko.toJS
ko.toJSON
之后调用,导致错误。
您的原型上的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
值放在函数后面(可以作为observable的子属性)。当您的结构被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);
});
}
};