Skip to content

Reactive Dialogs #8

@thomasnield

Description

@thomasnield

One of the pain points I've had with Rx and JavaFX is putting a dialog somewhere in the middle of an Observable chain, usually to prevent emissions from going forward on some condition. It's messy and maybe I'm just not competent enough with maintaining modality, and I struggle to get it right.

But I found an interesting pattern that seems to work consistently: Make the dialog return an Observable of the result. Note I am using TornadoFX in this example.

class YesNoConfirmDialog(val message: String) : Fragment() {
    override val root = BorderPane()
    var result: Observable<Response> by singleAssign()
    init {
        with(root) {
            top {
                label(message)
            }
            center {
                hbox {
                    alignment = Pos.BASELINE_CENTER
                    result = Observable.concat(
                            button("YES").actionEvents().map { Response.YES },
                            button("NO").actionEvents().map { Response.NO }
                    ).take(1).doOnCompleted { this@YesNoConfirmDialog.closeModal() }
                }
            }
        }
        openModal()
    }
    enum class Response { YES, NO }
}

Then all I have to do is flatMap() to this dialog's result property which will emit as an Observable<Response>.

sourceObservable
    .flatMap { YesNoConfirmDialog("Are you sure you want item $it to be committed?").result }
    .subscribe { println("You selected $it") }

I would hate to build dialogs from scratch like I did above. It would be ideal to put extension functions on existing JavaFX dialogs that return the Observable. This may be worth exploring.

It might be even better to create simple functions that take care of creating and returning the result of dialogs.

sourceObservable
    .flatMap { yesNoConfirmDialog("Are you sure you want item $it to be committed?") }
    .subscribe { println("You selected $it") }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions