MVC Pattern with Javascript

By on 6/3/2009

We’ve been pushing pretty hard at work recently to become masters of the javascript language.  Since we use it so extensively, and recent browser improvements such as compilation to native code of javascript … it means that it’s certainly not going away.  On the server-side, we use ASP.NET MVC and have come to be quite fond of the pattern. I wanted to explore what it would look like to use the MVC pattern in javscript so that we can use it some of our more complex pages.

The first thing I did was poke around on the web to see if there were any existing frameworks I could simply use.  I found a few such as:

Most of what I saw was either a bit too heavyweight for my tastes, or had the wrong focus, such as moving databinding from the server to the client.  So I decided to try my hand at implementing it for myself. 

The sample app/page that I implemented was a super simple list application that lets you type in some text, which gets sent to the server in an ajax call.  The status of the operations would be collected in a list on the page.  Although this is a fairly simplistic example, it has enough moving parts to show off the pattern.

The Dependencies

jQuery, my favorite uber framework of choice.

I tried to make this as simple of an example as possible. However, I recently purchased the book “Pro JavaScript Design Patterns, and there was a pattern in there that I really liked and wanted to use.  This pattern is the observer pattern.  I didn’t take the full code provided in the book, just what I needed.

//-- publisher class --
function Publisher() {
    this.subscribers = [];
};

Publisher.prototype.deliver = function(data) {
    this.subscribers.forEach(function(fn) { fn(data); });
};

//-- subscribe method to all existing objects
Function.prototype.subscribe = function(publisher) {
    var that = this;
    var alreadyExists = publisher.subscribers.some(function(el) {
        if (el === that) {
            return;
        }
    });

    if (!alreadyExists) {
        publisher.subscribers.push(this);
    }
    return this;
};

I used this so that the model can essentially raise events that the controller can listen to.

The View

Getting started, the first thing I implemented was the view.  I started with a few very simple html elements.

<input type="text" id="name" />
<input type="button" value="add" id="addButton" />
<ul id="list">
</ul>

Then I implemented the view.  Note that I’m using the literal object notation instead of the classic object oriented syntax to declare these classes.  I did this because I only need one instance of these classes.

var view = {

    init: function() {
        this.name = $("#name");
        this.addButton = $("#addButton");
        this.list = $("#list");

        this.addButton.click(function() {
            controller.addItem(view.name.val());
        });
    },

    appendItemToList: function(item) {
        this.list.append($("<li>").text(item));
    }
};

The init function uses jquery to pull references to the UI elements and also to set event handlers.  It also exposes the “appendItemToList” function, which concerns itself with taking a line of text and adding it to the list.

The Model

Next, I wrote the model, which would be responsible for communicating with the server in this case.  All of the issues surrounding server communication would be handled in this class (ie. ajax calls, callbacks, etc.). 

var model = {

    itemAddedEvent: new Publisher(),

    submitNewItem: function(item) {
        $.getJSON("/home/addnewitem/" + escape(item), null, this.submitNewItemCallback);
    },

    submitNewItemCallback: function(data) {
        model.itemAddedEvent.deliver(data.result);
    }
};

Note also that there is an itemAddedEvent which uses the Publisher class defined above.  This is used so that the model can notify the controller once the ajax call has returned.

The Controller

Finally, the controller … which can contain all of the business logic for the page without having to be muddied up with any knowledge of the page’s html structure, or any knowledge of how to communicate with the server.

var controller = {

    addItem: function(item) {
        var valueToDisplay = 'entered: ' + item;
        view.appendItemToList(valueToDisplay);
        model.submitNewItem(item);
    },

    serverItemAdded: function(item) {
        view.appendItemToList(item);
    },

    init: function() {
        this.serverItemAdded.subscribe(model.itemAddedEvent);
    }
};

The server-side action method is defined as such using ASP.NET MVC:

public ActionResult AddNewItem(string id)
{
    return Json(new
    {
        result = string.Format("'{0}' was added by the server", id)
    });
}

Putting it all together

The last bit is simply some glue code that lets the view and controller initialize themselves.

$(document).ready(function() {
    view.init();
    controller.init();
});

As you can see, with just a few very simple techniques, the code ends up very clean and easy to maintain.  Although for smaller/simple forms even this would probably end up being way too much complexity … some of the more complex forms will certainly benefit from the added separation of concerns.

I would love to get feedback on pros/cons of this approach.  Any alternative ideas would greatly be appreciated :-)

See more in the archives