I've recently started to delve into MVVM architectural pattern. I've understood large parts of it but still few doubts remain regarding how much responsibility ViewModel should take on behalf of View.
In other words, how dumb should View be?
For example, for simple state coordination like clearing TextView
after user presses SubmitButton
. This kind of state coordination requires no more than one-liner to implement using some of the popular data-binding frameworks.
For example in pseudo-ReactiveCocoa:
textView.text <~ submitButton.pressed.map { _ in "" }
However, Martin Fowler wrote in his Presentation Model,
The Presentation Model contains the logic that says that the composer field is only enabled if the check box is checked, so the when the view updates itself from the Presentation Model, the composer field control changes its enablement state
which suggests that even the simple logic like clearing out TextView
after pressing Button
should be encapsulated inside ViewModel
.
Such design choice leads to something like this (again, in pseudo-ReactiveCocoa):
// In View
viewModel.submitButtonPressed <~ submitButton.pressed
textView.text <~ viewModel.textViewText
// In ViewModel
textViewText <~ viewModel.submitButtonPressed.map { _ in "" }
Although it leads to better encapsulation of logics while assuming view with the job of binding only (making it dumb), it does make code a lot more verbose and lead to tighter coupling between View
and ViewModel
(by requiring ViewModel
to be aware of SubmitButton
).
I'm still new to MVVM pattern in general and learning stuff every day.
How much responsibility should ViewModel take?
In other words, must View
be completely dumb and only handle simple binding (connect its UI elements to bindable property provided by ViewModel
) or is it okay for View
to handle fairly simple logic like the above?
On a side note, is tight coupling between View
and ViewModel
okay in MVVM?
In general, the ViewModel
takes all responsibility. More specifically, in your scenario, the ViewModel
wouldn't know about the submitButton
, but rather the View
would know that the ViewModel
exposes a command (an ICommand
) called SubmitCommand
, and have the submitButton
bind to that command.
Sometimes it can get a bit more involved to completely separate the actions and corresponding logic, for instance when there's no binding available for a command for a specific event. But in those cases a fairly simple attached behavior (i.e. InvokeCommandAction
and friends, see the documentation) can bridge that gap to coax flow so the logic can go in to the ViewModel
.
Very rarely, there are scenarios (of which none come to mind currently) where it gets so involved that I just skip the whole idea, and separate as much as possible, rather than to have to work out three months later exactly what the hell is going on. But those cases are rare indeed.