Model-View-Controller (MVC) with JavaScript

The article describes an implementation of Model-View-Controller software design pattern in JavaScript.

I like JavaScript programming, because it is the most flexible language in the world. With the JavaScript language developers can create applications either in procedural or object-oriented style. It supports almost all programming styles and techniques that I know. I've seen procedural, object-oriented, aspect-oriented JavaScript code snippets. A determined developer can even use functional programming techniques in JavaScript applications.

My goal for this article is to write a simple JavaScript component that can show a power of the language. The component is a kind of the HTML ListBox ("select" HTML tag) control with an editable list of items: the user can select item and remove it or add new items into the list. Component will consist of three classes that implement the Model-View-Controller design pattern.

I hope, this article can be just a good reading for you, but it would be much better if you consider running the example and adapting it to you needs. I believe you have everything to create and run JavaScript programs: brains, hands, text editor (notepad), and Internet browser (IE or Firefox).

The Model-View-Controller pattern, which I'm about to use in the code, requires some description here. As you may know, the name of the pattern is based on the names of its main parts: Model, which stores an application data model; View, which renders Model for an appropriate representation; and Controller, which updates Model. Wikipedia defines typical components of the Model-View-Controller architecture as follows:

  • Model: The domain-specific representation of the information on which the application operates. The model is another name for the domain layer. Domain logic adds meaning to raw data (e.g., calculating if today is the user's birthday, or the totals, taxes and shipping charges for shopping cart items).
  • View: Renders the model into a form suitable for interaction, typically a user interface element. MVC is often seen in web applications, where the view is the HTML page and the code which gathers dynamic data for the page.
  • Controller: Processes and responds to events, typically user actions, and invokes changes on the model and perhaps the view.

The data of the component is a list of items, in which one particular item can be selected and deleted. So, the model of the component is very simple - it is stored in an array property and selected item property; and here it is:

/**
 * The Model. Model stores items and notifies
 * observers about changes.
 */
var ListModel = function (items) {
	this._items = items;
	this._selectedIndex = -1;

	this.itemAdded = new Event(this);
	this.itemRemoved = new Event(this);
	this.selectedIndexChanged = new Event(this);
};

ListModel.prototype = {

	getItems : function () {
		return [].concat(this._items);
	},

	addItem : function (item) {
		this._items.push(item);
		this.itemAdded.notify({item: item});
	},

	removeItemAt : function (index) {
		var item = this._items[index];
		this._items.splice(index, 1);
		this.itemRemoved.notify({item: item});
		if (index == this._selectedIndex)
			this.setSelectedIndex(-1);
	},

	getSelectedIndex : function () {
		return this._selectedIndex;
	},

	setSelectedIndex : function (index) {
		var previousIndex = this._selectedIndex;
		this._selectedIndex = index;
		this.selectedIndexChanged.notify({previous: previousIndex});
	}

};  

Event is a simple class for implementing the Observer pattern:

var Event = function (sender) {
	this._sender = sender;
	this._listeners = [];
};

Event.prototype = {
	attach : function (listener) {
		this._listeners.push(listener);
	},
	notify : function (args) {
		for (var i = 0; i < this._listeners.length; i++) {
			this._listeners[i](this._sender, args);
		}
	}
};

The View class requires defining controls for interacting with. There are numerous alternatives of interface for the task, but I prefer a most simple one. I want my items to be in a Listbox control and two buttons below it: "plus" button for adding items and "minus" for removing selected item. The support for selecting an item is provided by Listbox's native functionality. A View class is tightly bound with a Controller class, which "... handles the input event from the user interface, often via a registered handler or callback" (from wikipedia.org).

Here are the View and Controller classes:

var ListView = function (model, controller, elements) {
	this._model = model;
	this._controller = controller;
	this._elements = elements;

	var _this = this;

	// attach model listeners
	this._model.itemAdded.attach(function () {
		_this.rebuildList();
	});
	this._model.itemRemoved.attach(function () {
		_this.rebuildList();
	});

	// attach listeners to HTML controls
	this._elements.list.change(function (e) {
		_this._controller.updateSelected(e);
	});

};


ListView.prototype = {

	show : function () {
		this.rebuildList();
		var e = this._elements;
		var _this = this;
		e.addButton.click(function () { _this._controller.addItem() });
		e.delButton.click(function () { _this._controller.delItem() });
	},

	rebuildList : function () {
		var list = this._elements.list;
		list.html('');
		var items = this._model.getItems();
		for (var key in items)
			list.append($('<option>' + items[key] + '</option>'))
		this._model.setSelectedIndex(-1);
	}

};

var ListController = function (model) {
	this._model = model;
};

ListController.prototype = {

	addItem : function () {
		var item = prompt('Add item:', '');
		if (item)
			this._model.addItem(item);
	},

	delItem : function () {
		var index = this._model.getSelectedIndex();
		if (index != -1)
			this._model.removeItemAt(this._model.getSelectedIndex());
	},

	updateSelected : function (e) {
		this._model.setSelectedIndex(e.target.selectedIndex);
	}

};

And of course, the Model, View, and Controller classes should be instantiated. The sample, which you can below, uses the following code to instantiate and configure the classes:

$(function () {
	var model = new ListModel(['PHP', 'JavaScript']);
	var view = new ListView(model, new ListController(model),
		{
			'list' : $('#list'), 
			'addButton' : $('#plusBtn'), 
			'delButton' : $('#minusBtn')
		}
	);
	view.show();
});
<select id="list" size="10" style="width: 15em"></select><br/>
<button id="plusBtn">  +  </button>
<button id="minusBtn">  -  </button>

Example:


Very Rare Article

Thanks for the source code. I'll remember your name.

Very Nice Breakdown

Hi Alex,

Thanks for this great article. It seems that it is very difficult to find something on the net that breaks down the MVC pattern for JavaScript implementation in the simplicity and detail that you've presented here.

I know there are a number of JavaScript frameworks around now that will do what you've described here for you but it is nice (as a developer) to understand what is going on at the basic level. As a server side PHP developer who is used to MVC on the server side, it has been a bit of a challenge to wrap my head around MVC in JavaScript since it is a much more 'live' environment as oppose to the request-response protocol of server side languages.

I was wondering which JS MVC framework (if any) you prefer/like/would recommend? I have read about a few but most seem too complex for what I need. At the moment I am not writing anything too complex but I'd still like to structure my code in MVC. If there is a simple and lightweight JS MVC framework/library then I'd like to use that otherwise I'll probably try and implement stuff using this article (btw if you know of any other articles that are similar to this one then please let me know).

Thanks
Ziad

p.s. my contact is ziad underscore mannan at hotmail dot com

Check out JavaScriptMVC

Great article, you might want to check out JavaScriptMVC. http://javascriptmvc.com

I’m Alex Netkachov and I welcome you on my site, which is my technical playground and web log.

User login