5

ドキュメントに記載されている手順に従って、次のビューモデルを使用します。

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は実際にエラーを次のように報告します。

Uncaught RangeError:最大呼び出しスタックサイズを超えました

ko.mapping.toJS(self)の代わりにを使用するとko.toJS(self)、少しわかりやすいエラーが表示されますが、実際のエラー「メッセージ」は表示されません。

無限ループエラー

ko.toJS(self)のようなものと交換すると{ Name: self.Name(), Address: self.Address() /* etc */ }、すべてが正常に機能します。メソッドを変換しようとしてSaveいて、結果としてメソッドを再呼び出ししているようです。

KnockoutJSにバグがあるか、KnockoutJSの使用方法に問題があります。私は後者を好みます。考え?

4

1 に答える 1

14

コードに問題があることがわかりました。 ko.toJSオブジェクト内の関数を保持するため、オブジェクトを適切にマッピングできます。ただし、jqueryはデータオブジェクトのすべての関数を呼び出して値を取得しようとします。これにより、無限ループが発生します。

Saveマップされないように関数にフラグを立てる必要があります。残念ながら、toJS関数はそれを実行できないようです。オブジェクトのすべてのメンバーを保持します。幸いなことに、マッピングプラグインを使用するとそれが可能になります。

メンバーを除外するには、ignoreオプションをを含む配列に設定すると、マップ時'Save'にメンバーが無視されます。Save

var data = ko.mapping.toJS(self, {
    ignore: ['Save']
});

マッピングプラグインを使用していない場合はSave、JSオブジェクトから関数を削除するオプションが常にあります。

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
    });
};
于 2012-09-05T20:24:27.100 に答える