Я пытаюсь использовать 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();
});
По сути, я объединяю два потока. Один поток нажатий на кнопку, который фильтруется по состоянию виджета, где состояние «NotInEditMode». И еще один поток нажатий на кнопку, отфильтрованный до противоположного состояния, плюс проецируется в поток возвращаемого значения диалога. Обратите внимание, что возвращаемое значение диалога является AsyncSubject объекта bool, который представляет данный ответ.
Теперь сложная часть! Это не работает таким образом! Зачем? Поскольку, когда состояние «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 для вещей, для которых он не предназначен; -)