-
Notifications
You must be signed in to change notification settings - Fork 27
View Model Patterns
-
Data & View (impractical, not recommended)
This is the most basic working example and is here only to demonstrate the minimum code required. If you ever need to monkey-patch a solution without causing view layer breakage or resorting to manual DOM manip, jQuery, etc., this is good to keep in mind.
// some data var name = "Jack"; var age = 33; // view constructor function MyView() { // view closure return function() { // render() return ["div", // template ["strong", name], ["em", age], ]; }; } // init the 'view model' (vm) and render it to DOM var vm = domvm(MyView).mount(document.body); // now we can update the data & redraw the view age = 42; vm.redraw();
-
Disjoint Model & View
Reworking the example above, we wrap the same data in an object (our basic model) and explicitly pass the model into the view during init. This way, you don't need to rely on data being in-scope of the view definition; of course nothing stops you from using both in-scope data and an explicit model.
// the model can be any object or array and can expose // whatever domain API, methods or properties you need var myModel = {name: "Jack", age: 33}; // the view closure can hold any needed view state and // should return a template-generating `render` function // or an object containing it: {render: function() {}} function MyView(vm, model) { // passed-in model lands here return { render: function() { return ["div", ["strong", model.name], ["em", model.age], ]; } } } // init the 'view model' (vm) and render it to DOM var vm = domvm(MyView, myModel).mount(document.body); // pass model into init // now we can update the model & redraw the view myModel.age = 42; vm.redraw();
-
Model-Integrated Binding
Building on the concepts above, you can choose to create a constructor-based model that incorporates a view-model binding.
function Person(name, age) { this.name = name; this.age = age; this.viewOne = [PersonView, this]; // view-model binding } function PersonView(vm, person) { person.vm = vm; // export the vm, so we can call <person>.vm.redraw() externally return { render: function() { return ["div", ["strong", person.name], ["em", person.age], ]; } } } var jack = new Person("Jack", 33); domvm(jack.viewOne).mount(document.body); jack.age = 42; jack.vm.redraw();
-
Model-Integrated View
More monolithic still, you can wrap the view definition itself in the constructor closure and keep everything private. This is also not very practical, but here to demonstrate what can be done.
function Person(name, age) { var vm0; function PersonView(vm) { vm0 = vm; return { render: function() { return ["div", ["strong", name], ["em", age], ]; } } } this.renderTo = function(el) { domvm(PersonView).mount(el); }; this.setAge = function(newAge) { age = newAge; vm0.redraw(); }; } var jack = new Person("Jack", 33); jack.renderTo(document.body); jack.setAge(42);