将knockout对象转换为纯JavaScript对象时的无限循环

时间:2012-09-05 19:41:07

标签: knockout.js

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),那么我会得到一个更具启发性的错误,但没有真正的错误“消息”:

infinite loop error

如果我将ko.toJS(self)换成{ Name: self.Name(), Address: self.Address() /* etc */ }之类的东西,那么一切正常。似乎它正在尝试转换Save方法并重新调用该方法。

KnockoutJS中存​​在一个错误,或者当我使用它时出现问题。我更喜欢后者。思考?

1 个答案:

答案 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
    });
};