documentation中给出的Folliwing说明,我有以下视图模型:
var newContactViewModel = function () {
var self = this;
self.Name = ko.observable();
self.Address = ko.observable();
self.City = ko.observable();
self.State = ko.observable();
self.PostalCode = ko.observable();
self.Save = function () {
$.ajax({
type: "POST",
url: "/contact",
data: ko.toJS(self), //infinite loop here
success: state.OnSaved
});
};
};
调用self.Save
方法时,会发生无限循环。 Chrome实际上将错误报告为:
未捕获RangeError:超出最大调用堆栈大小
如果我使用ko.mapping.toJS(self)
代替ko.toJS(self)
,那么我会得到一个更具启发性的错误,但没有真正的错误“消息”:
如果我将ko.toJS(self)
换成{ Name: self.Name(), Address: self.Address() /* etc */ }
之类的东西,那么一切正常。似乎它正在尝试转换Save
方法并重新调用该方法。
KnockoutJS中存在一个错误,或者当我使用它时出现问题。我更喜欢后者。思考?
答案 0 :(得分:14)
我发现了代码的问题。 ko.toJS
保留对象中的函数,以便能够正确映射它。但是,jquery将调用数据对象上的所有函数来尝试获取值。这反过来导致无限循环。
您需要将Save
函数标记为不映射。不幸的是toJS
函数似乎无法做到这一点。它将保留对象的所有成员。幸运的是,映射插件允许您这样做。
要排除成员,请将ignore
选项设置为包含'Save'
的数组,并在映射时忽略Save
成员。
var data = ko.mapping.toJS(self, {
ignore: ['Save']
});
如果你没有使用映射插件,你总是可以选择从JS对象中删除Save
函数。
self.Save = function () {
$.ajax({
type: "POST",
url: "/contact",
data: self.ToData(),
success: state.OnSaved
});
};
self.ToData = function () {
var data = ko.toJS(self);
delete data.Save; // remove functions
delete data.ToData;
return data;
};
另一方面,我建议不要尝试使用视图模型实例作为调用的数据。我会明确地创建数据对象。当然它有可能很长,但这种方法很可能总能奏效。
self.ToData = function () {
return ko.toJS({
Name: self.Name,
Address: self.Address,
City: self.City,
State: self.State,
PostalCode: self.PostalCode
});
};