Model-View-ViewModel (MVVM)
Add a ViewModel between your Model and View that handles all the UI state β data binding wires them together so the View just reacts to changes.
Intent & Description
π― Intent
Remove all UI logic from the View so it becomes a pure, dumb display layer driven entirely by the ViewModel.
π Context
You’re working in a framework with rich data-binding (Angular, Vue, React, WPF). Your Views contain logic they shouldn’t β conditional rendering, state management, formatting β making them hard to test and maintain.
π‘ Solution
Three components:
- Model β pure data and domain logic, no UI awareness.
- ViewModel β transforms Model data into View-ready format, exposes observable properties and commands, handles all UI state.
- View β binds to ViewModel properties and commands, contains zero logic.
Data binding does the wiring β View updates when ViewModel changes, ViewModel commands respond to user actions.
Real-world Use Case
π TL;DR
ViewModel holds all the UI state and logic. View just binds to it and reacts. Test the ViewModel without ever touching a browser. Heavy for simple UIs, gold for complex ones.
Advantages
- ViewModels are pure JS/TS classes β unit testable with zero UI framework dependencies.
- Perfect designer-developer split: designers own the View, devs own the ViewModel.
- Same ViewModel can drive a web view, mobile view, or widget without changes.
Disadvantages
- Two-way binding bugs are painful to trace β change propagation can loop in unexpected ways.
- Total overkill for simple forms or static UIs with minimal state.
// ViewModel with basic data binding simulation
class ViewModel {
constructor(model) {
this.model = model;
this.bindings = [];
}
setUserName(name) {
this.model.name = name;
this.notifyBindings();
}
bind(element, prop) {
this.bindings.push({ element, prop });
}
notifyBindings() {
this.bindings.forEach(b => {
b.element[b.prop] = this.model.name;
});
}
}