いくつかの GUI シナリオで RxJS を使用しようとしています。興味深い事例に出会いました。エンティティを表示、編集、作成できるウィジェットがあります。
「AddNewEntity」ボタンをクリックしたとき。editwidget は空のエンティティを作成し、それをロードして編集モードに変更します。ただし、既に編集モードになっている場合は、最初に変更を元に戻すかどうかを尋ねるメッセージが表示されます。[はい] をクリックすると、前に説明したのと同じことが起こります。
だから私はRxがそれで私を助けるかもしれないと思った. これがコードです。
Rx.Observable.Merge([
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isNotInEditMode),
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isInEditMode)
.Select(function (id) {
return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
.Where(function (answer) { return answer === true; });
})
.Switch()
])
.Subscribe(self, function () {
var entity = createNewEntity();
editWidget.loadEntity(currentEntity);
editWidget.setEditMode();
});
基本的に、2 つのストリームをマージしています。状態が「NotInEditMode」であるウィジェットの状態によってフィルタリングされるボタンへのクリックの 1 つのストリーム。また、反対の状態にフィルター処理されたボタンへの別のクリック ストリームが、ダイアログの戻り値ストリームに射影されます。ダイアログの戻り値は、指定された回答を表す bool の AsyncSubject であることに注意してください。
今、トリッキーな部分です!このようには機能しません!なんで?状態が「NotInEditMode」の場合、最初のストリームが一致するため、ウィジェットが編集モードに設定され、2 番目のストリーム (マージ内の順序のために後で実行される) も一致し、基本的に完全に矛盾した状態になります (ロックされていない編集モードと開いているダイアログ)。
私はそれを修正する2つの方法を見つけました。最初のものは、マージ内の順序を次のように変更します。
Rx.Observable.Merge([
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isInEditMode)
.Select(function (id) {
return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
.Where(function (answer) { return answer === true; });
})
.Switch(),
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isNotInEditMode)
])
.Subscribe(self, function () {
var entity = createNewEntity();
editWidget.loadEntity(currentEntity);
editWidget.setEditMode();
});
ただし、このソリューションは嫌いです。読者には明らかではありません。
幸いなことに、別の解決策を見つけました。
Rx.Observable.Merge([
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isNotInEditMode),
editWidget.getObservable('AddNewEntityButtonClicked')
.Where(isInEditMode)
.Select(function (id) {
return dialogWidget.question("Reject Changes?", "You are in edit mode. Reject Changes?")
.Where(function (answer) { return answer === true; });
})
.Switch()
])
.Take(1)
.Repeat()
.Subscribe(self, function () {
var entity = createNewEntity();
editWidget.loadEntity(currentEntity);
editWidget.setEditMode();
});
背後にある考え方は、進むべき道は 1 つしかないため、最初に一致したシナリオで他のすべてのシナリオを中止する必要があるというものです。
ただし、よりクリーンなソリューションがあるのではないか、それとも設計されていないものに Rx を使用しようとしているのだろうか ;-)