Towards MVC without a framework

For many projects, MVC frameworks like angularjs are a godsend. When you are working on something a little smaller though, these frameworks tend to get in the way. They feel like cracking a nut with a sledgehammer. I found myself searching for something far far simpler. Something that worked with POJSOs (plain old javascript objects) instead of forcing my objects to conform to a framework.

On my quest I came across a great article that discussed the idea of implementing MVC without a framework. I know it sounds odd to start with, but as I thought about this further, all these frameworks were making my leff less than pleasant. If I wanted to move my model from one framework to another it required a significant rethink and refactor urggghhh!

At the same time, there has been some development happening in this space with the announcement that Chrome 36 has been released. Chrome 36 includes support for a new way of binding to objects using Object.observe(). Addy Osmani is certainly pretty excited about it and predicts a Data Binding Revolution

A Simple Demo

I have put together a really simple example on jsfiddle to have a look at.

I decided to make a (very) simple calculator:

function SumCalculator(){
    var that = this;
    this.Operand1 = 0;
    this.Operand2 = 0;
    this.Result = 0;
    this.performCalculation = function(){
        that.Result = Number(that.Operand1) + Number(that.Operand2);   
    }
    
    var observer = new CompoundObserver();
    observer.addPath(this, 'Operand1');
    observer.addPath(this, 'Operand2');
    observer.open(this.performCalculation);
}

It's a simple calculator that can add 2 numbers. Things might be a bit unfamiliar when we get to the section:

	var observer = new CompoundObserver();
    observer.addPath(this, 'Operand1');
    observer.addPath(this, 'Operand2');
    observer.open(this.performCalculation);

This section of code uses the excellent library observe-js which is a wrapper around the Object.observe function that also polyfills older browser. Of course, it is possible to use Object.observe without this library, but the library adds a few convenience functions that make Object.observe a little easier to use.

Anyway, what we are doing here is creating a Compund Observer. This can observe multiple properties and trigger the same function on change. So, in our case, we observe both the operands and calculate the result if either of them change.

Now for the Controller:


var newCalculator = new SumCalculator();
function setResult(){
   
    document.getElementById("Result").value = newCalculator.Result;
}
setResult();

var observer = new PathObserver(newCalculator, 'Result');
observer.open(setResult);

var inputOperand1 = document.getElementById("Operand1");
inputOperand1.value = newCalculator.Operand1;
inputOperand1.addEventListener("keyup", function(){
    newCalculator.Operand1 = inputOperand1.value;
})

var inputOperand2 = document.getElementById("Operand2");
inputOperand2.value = newCalculator.Operand2;
inputOperand2.addEventListener("keyup", function(){
    newCalculator.Operand2 = inputOperand2.value;
})

We start by creating the controller and creating a function that will transfer the result from the calculator object to the html view. We then create a new observer that will watch the result of the calculator and transfer it to the view whenever the result changes.

The rest of the code is concerned with waiting for changes in either of the operands and passing them to the calculator.

Pretty Simple Eh!

One of the things I really like about using observers is that you don't have to mangle your objects to suit the framework you are using. This allows for much more flexibility in object composition and reusability. In my utopia models should be shared amongst different frameworks rather than rewriting them when we make an architectural change.

But what about performance? That's the good news, the performance of this native solution to observing objects is awesome. Check out the performance graphs near the end of Addy Osmani's Article.

If you want to beef up your MVC a little without adding too much burden, there's also a great two-way data binding library Rivets which handles alot of the plumbing between the view and your code. At the time of writing, it doesn't currently include built in support for Object.observe but it can be easily added. The author of Rivets is planning to add Object.observe support natively so by the time you read this, it may already be there.

Another framework that I haven't used personally but supports Object.observe out of the box is the polymer project. The Object.observe polyfill I used in my example above is part of the polymer project. Initially, when I looked at it I though it would be just another bloated framework but from my reading of the documentation, I am pleseantly surprised. First of all data binding is supported using POJSOs, Big Tick. Second, you can take as little or as much of the framework as you like. Third, it supports Web Components in conjunction with MVC so you can roll your own reusable components or use the ones that are supplied. It also includes a pretty neat layout engine. I am still unsure about how this framework will feel on a small project, but I will give it a try on my next one.