Eureka: Where does Eureka forms fit within MVVM?

Created on 19 Jul 2018  路  3Comments  路  Source: xmartlabs/Eureka

I've see various examples where the form is built in the VC, some parts in the VM, and bound with Rx.

But is there a proper "elegent" technique to employ using this form engine?
How _do you_ integrate the Eureka forms engine properly into the MVVM architecture?

Most helpful comment

We did not design Eureka with MVVM in mind but we have used it in MVVM.

We had a ViewModel with one variable for each value in the form (i.e. one for each row).

final class RegisterViewModel {
    private(set) open var formValues: Variable<[String : Any?]>
    private(set) var firstLastName: String = ""
    private(set) var dateOfBirth: Date = Date()

    // plus some helper functions and vars
}

We created the form in the View part of the architecture, more specifically in the ViewController. Then we populated the rows with the values from the ViewModel.

<<< TextRow(RegisterViewModel.RowTags.firstLast) {
                $0.value = viewModel.firstLastName
                $0.title = "Name"
                $0.add(rule: RuleMinLength(minLength: viewModel.nameMinLength))
            }
            <<< DateInlineRow(RegisterViewModel.RowTags.dateOfBirth) {
                $0.value = viewModel.dateOfBirth
                $0.title = "Date of birth"
            }

We had an Rx observable to watch the values in the ViewModel which was used to update the form when the ViewModel changed.

viewModel.formValues.asObservable()
            .subscribe(onNext: { [weak self] formValues in
                self?.updateForm(with: formValues)
            })
            .addDisposableTo(disposeBag)

Finally on submit of the form we'd call a function with the new values of the form.

self?.viewModel.submit(values: self!.form.values())

I hope this brief description can help you setting up your forms. I omitted parts of the code but I think you will find your way.

All 3 comments

We did not design Eureka with MVVM in mind but we have used it in MVVM.

We had a ViewModel with one variable for each value in the form (i.e. one for each row).

final class RegisterViewModel {
    private(set) open var formValues: Variable<[String : Any?]>
    private(set) var firstLastName: String = ""
    private(set) var dateOfBirth: Date = Date()

    // plus some helper functions and vars
}

We created the form in the View part of the architecture, more specifically in the ViewController. Then we populated the rows with the values from the ViewModel.

<<< TextRow(RegisterViewModel.RowTags.firstLast) {
                $0.value = viewModel.firstLastName
                $0.title = "Name"
                $0.add(rule: RuleMinLength(minLength: viewModel.nameMinLength))
            }
            <<< DateInlineRow(RegisterViewModel.RowTags.dateOfBirth) {
                $0.value = viewModel.dateOfBirth
                $0.title = "Date of birth"
            }

We had an Rx observable to watch the values in the ViewModel which was used to update the form when the ViewModel changed.

viewModel.formValues.asObservable()
            .subscribe(onNext: { [weak self] formValues in
                self?.updateForm(with: formValues)
            })
            .addDisposableTo(disposeBag)

Finally on submit of the form we'd call a function with the new values of the form.

self?.viewModel.submit(values: self!.form.values())

I hope this brief description can help you setting up your forms. I omitted parts of the code but I think you will find your way.

My setup is very similar, except could you elaborate how exactly you work with the formValues variable?

As I've had binding issues that don't update the form UI automatically and am forced to row.reload() within .onChange.

The ViewModel subscribes to the changes in the Model and updates its variables (firstLastName, dateOfBirth) and its formValues accordingly.

As shown above the ViewController subscribes to the formValues and calls updateForm(with: formValues).

This method then calls:

form.setValues(values)
tableView?.reloadData()

There might be a better way than reloading the whole table.

Does that work for you?

Was this page helpful?
0 / 5 - 0 ratings