区分可能的流,寻找干净的解决方案
我正在尝试在某些 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 来做它不适合的事情;-)
I'm trying to use RxJS in some GUI scenarios. I came across an interesting case.
I have a widget where one can view, edit and create entities.
When you click on the "AddNewEntity" Button. The editwidget creates an empty entity, loads it and changes into edit mode. However, if you are already in edit mode, it kindly askes if you like to revert changes first and once you clicked "yes" the same happens as described earlier.
So I thought Rx might help me with that. Here is the code.
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();
});
Basically I'm merging two streams. One stream of clicks to the button which is filtered by the state of the widget where the state is "NotInEditMode". And another stream of clicks to the button that is filtered to the opposite state plus is projected into the return value stream of the dialog. Notice that the return value of the dialog is an AsyncSubject of bool which represents the given answer.
Now the tricky part! It doesnt work this way! Why? Because when the state is "NotInEditMode", the first stream matches, it sets the widget into edit mode and now the second stream (which runs afterwards because of the order inside the merge) will also match which basically results into a completly inconsitent state (unlocked edit mode plus open dialog).
I found two ways to fix it. The first one, change the order inside the merge so that it looks like this:
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();
});
However, I dislike this solution. It's not obvious to the reader.
Fortunatly, I found another solution:
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();
});
The idea behind is that there can only be one way to go so the first matching scenario should abort all others.
However, I wonder if there might be a cleaner solution or if I'm trying to use Rx for things it wasnt designed for ;-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我想我找到了一个干净的解决方案:
I think I found a clean solution: