なんてこった。あなたのコードに大きな問題があります!詳細を掘り下げる前に、ページから飛び出すのは、episodes
配列が変更されるたびに、配列内のすべてのエピソードにサブスクリプションを繰り返し追加する可能性があることです。うわぁ!
イベント伝播の遅延
私の不安について説明する前に、リスナーが発火したときと の値との間に矛盾があるというあなたの具体的な経験を認めたいと思いますmanager.hasChanges
。それは本当です。KO サブスクリプションは、 が変更について聞く前に発火しEntityManager
ています ... これが false を報告する理由です。マネージャーが聞くには、変更のニュースはまだ届いていません。
私もこれに気づきました。実際、TodoSampleのviewModel.jssetTimeout
を見ると、 Breeze に変更を聞く機会を与えるために を追加することで、この問題を回避していることがわかります。
// Breeze PropertyChanged イベントで変更をリッスンします
item.entityAspect.propertyChanged.subscribe(function () {
if (suspendItemSave) { return; }
// EntityManager に変更を聞く時間を与える
setTimeout(saveIfModified, 0);
関数 saveIfModified() {
if (item.entityAspect.entityState.isModified()) {
dataservice.saveChanges();
}
}
});
別の方法を知りたいです。これは、KO と Breeze の間のタイミングの問題です。私たちはまだそれを巧みに処理する方法を考え出していません. できるかどうかわかりません。
モデルルールまたはビュールール?
バックアップしましょう。どのビューに表示されていても、プロパティが変更episode
されたときに保存することになっていますか? 答えが「はい」の場合、モデルに本当に属しているアプリケーション ビジネス ルールがあり、エピソードの変更をリッスンする何かが本当に必要です。listenedTo
しかし、答えが「いいえ」の場合...保存がオブジェクトの変更ではなく「チェックボックス」によってトリガーされる場合、これはUIルールです...ビュールール...そしてKOを使用する必要がありますエピソードプロパティではなく、チェックボックスをリッスンします。
エンティティが変更されたときの保存
最初のケースで、アプリケーション ルールが次のようであると断言listenedTo
しましょう。
TodoSampleで、エンティティのプロパティの 1 つ (プロパティのいずれか) の変更を直接リッスンする方法を示したことは知っています。これは強力で直感的です。
それが最も安全な方法ではないと信じるようになりました。同じエンティティを共有する複数の ViewModel を持つアプリでメモリ リークが発生する可能性があります。この「Todo」アプリは画面が1つしかないので、そんな心配はありません。しかし、より大きなアプリでは...気になります。
したがって、プロパティへの変更をリッスンしないことをお勧めしEpisode
ます。代わりに、EntityManager
! 最近リリースされたBreeze SPA テンプレートのdatacontext.js からのこのスニペットを見てください。
関数 configureManagerToSaveModifiedItemImmediately() {
manager.entityChanged.subscribe(entityStateChanged);
関数 entityStateChanged(args) {
if (args.entityAction ===そよ風.EntityAction.EntityStateChange) {
var エンティティ = args.entity;
if (entity.entityAspect.entityState.isModified()) {
saveEntity(エンティティ);
}
}
}
}
EntityManager がキャッシュするエンティティの状態変化をリッスンする方法に注意してください。「変更済み」状態への遷移のみに関心があります。検出されると、エンティティが保存されます。
これは広すぎるかもしれません。ただし、アプリケーションの特定のニーズに合った追加のフィルタリング ロジックを登録することは想像できます。
セーブキューイング
自動保存に関する新しい問題。この問題は、保存をトリガーする方法に関係なく重要です。
ユーザーはかなり速くクリックできます。彼女は、処理できるよりも速く保存要求をトリガーすることになります。Breeze (デフォルト) はEntityManager
、保留中の保存操作からサーバーが結果を返すのを待っている間、再度保存することはできません。例外がスローされます。
保存が成功したかどうかがわかるまで、エンティティの状態を変更済みから未変更に変更できないため、待機する必要があります。保存に失敗した場合、エンティティを「保存されていない」状態のままにしておく必要があります。
のdatacontext.jsの上部を見てくださいmanager.enableSaveQueuing(true)
。これはBreeze 固有の機能ではありません。これはプラグインScripts/breeze.savequeuing.jsの機能 です。このプラグインをロードする必要があります。Breeze SPA テンプレートの記事でそれについて読んでください。
なぜそんなに複雑なのか
この Breeze のことは非常に複雑だと思うかもしれません。実際、複雑化を導入しているのは Breeze ではありません。複雑さを追加しているエンティティの状態が変化したときに保存をトリガーするのはあなたの望みです。
そうするのが間違っていると言っているのではありません。このアプローチは、実装に注意を払っている Breeze によって提供される機会であると言っています。
Breeze がなければ、エンティティの状態を追跡するのに時間がかかります。したがって、本当に安全な唯一のオプションは、チェックボックスへの変更に基づいて保存をトリガーすることです...この場合、チェックボックスへの KO バインディングよりも複雑ではありません。
setTimeout
まあ...わかりました...あなたがつまずいたBreeze / KOのタイミングの問題により、ギャンビットが必要になるため、もう少し複雑です。しかし、あなたが私の主張を理解してくれることを願っています。