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;
});
}
}