MVVM
Implementation of MVVM in JavaScript
by Jeremy Likness
HTML
<div id="myApp">
<label for="inputBox">Type Something:</label>
<input name="inputBox"/>
<div id="output">
Output Will Appear Here
</div>
</div>
JavaScript
(function() {
"use strict";
var view, viewModel, valueTemplate;
valueTemplate = {
configurable: false,
enumerable: true,
get: function() {
return this._value;
},
set: function(val) {
var i;
if (val !== this._value) {
this._value = val;
for (i = 0; i < this._listeners.length; i += 1) {
this._listeners[i]();
}
if (this.onChange) {
this.onChange();
}
}
}
};
// this is simply data and behavior. In this
// case a single property is tracked with an
// event fired when it changes
function ViewModel() {
this._listeners = [];
this._value = "";
}
Object.defineProperty(ViewModel.prototype, "text", valueTemplate);
ViewModel.prototype.attach = function(fn) {
this._listeners.push(fn);
};
// this is a data-binder for input boxes
function InputBinder(elem) {
var that = this;
this._listeners = [];
this._elem = elem;
elem.onkeyup = function() {
that.value = elem.value;
};
}
InputBinder.prototype.attach = function(fn) {
this._listeners.push(fn);
}
InputBinder.prototype.onChange = function() {
this._elem.value = this.value;
};
Object.defineProperty(InputBinder.prototype,
"value", valueTemplate);
// this is a data-binder for divs
function DivBinder(elem) {
this._listeners = [];
this._elem = elem;
}
DivBinder.prototype.attach = function(fn) {
this._listeners.push(fn);
}
DivBinder.prototype.onChange = function() {
this._elem.innerText = this.value;
};
Object.defineProperty(DivBinder.prototype,
"value", valueTemplate);
// the view simply attaches the data-bindings
function View(viewModel, ui) {
var inputBinder = new InputBinder(
ui.getElementsByTagName("input")[0]),
divBinder = new DivBinder(
ui.getElementsByTagName("div")[0]);
viewModel.attach(function() {
divBinder.value = viewModel.text;
});
...