我正在尝试在某些GUI场景中使用RxJS。我遇到了一个有趣的案例。我有一个小部件,可以在其中查看,编辑和创建实体。
当您单击"添加新实体"按钮时。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();
});
基本上我正在合并两个流。对按钮进行一次单击,该按钮按状态为"NotInEditMode"的小部件的状态进行过滤。而对按钮的另一个点击流被过滤到相反的状态加上被投影到对话框的返回值流中。请注意,对话框的返回值是表示给定答案的 bool 的 AsyncSubject。
现在是棘手的部分!这样行不通!为什么?因为当状态为"NotInEditMode"时,第一个流匹配,它将小部件设置为编辑模式,现在第二个流(由于合并内部的顺序而运行)也将匹配,这基本上导致完全不一致的状态(解锁编辑模式加上打开对话框)。
我找到了两种解决方法。第一个,更改合并中的顺序,使其如下所示:
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();
});
背后的想法是,只能有一种方法,因此第一个匹配方案应该中止所有其他方案。
但是,我想知道是否有更干净的解决方案,或者我是否尝试将 Rx 用于它不是为之设计的东西;-)
我找到了一个干净的解决方案:
editWidget.getObservable('NewButtonClicked')
.Select(function () {
return isInEditMode() ? dialogWidget.question("Reject Changes", "You are in edit mode. Reject Changes?)
.Where(function (answer) { return answer === true; }) : Rx.Observable.Return(true);
})
.Switch()
.Subscribe(function(){
currentEntity = options.createNewEntity();
editWidgetLoadEntity(currentEntity);
editWidget.enable();
});