What is MVC

MVC is an architectural design pattern which stands for Model-View-Controller and encourages improved application organization through a seperation of concerns. It enforces the isolation of business data (Models) from user interfaces (Views), with a third component (Controllers) traditionally managing logic and user-input.

Models

Models manage the data for an application. When a model changes, it will notify its observers(views) that a change has occured, so that they may react accordingly.

Views

Views are a visual representation of models that present a filtered view of their current state. A view typically observes a model and is notified when the model changes, allowing the view to update itself accordingly.

Controllers

Controllers are an intermidiary between models and views which are classically responsible for updating the model when the user manipulates the view.

 

MVC examples

Now that you have a basic understanding of what the MVC architecture is all about, let me show you some examples.

  1. The first example, is the typical “Hello world” example, which I copied from following stackoverflow question https://stackoverflow.com/questions/8497833/hello-world-in-mvc-pattern
  2. The second example renders a red rectangular on the page showing how model, view and controller communicate
  3. The last example adds some events and shows a very simplistic approach of a todo app.

Note that above examples are simplified for demonstrating purposes. For real “hello world” examples in the JS MVC world go take a look at todoMVC

A. Hello World

Here’s the most simplisticMVC example you could think of.

var M = {}, V = {}, C = {};

M.data = "hello world";

V.render = function (M) { alert(M.data); }

C.handleOnload = function () { V.render(M); }

window.onload = C.handleOnLoad;

Controller (C) listens on some kind of interaction/event stream. In this case it’s the page’s loading event.

Model (M) is an abstraction of a data source.

View (V) knows how to render data from the Model.

The Controller tells to View to do something with something from the Model.

In this example

  • the View knows nothing about the Model apart from it implements some interface
  • the Model knows nothing of the View and the Controller
  • the Controller knows about both the Model and the View and tells the View to go do something with the data from the Model.

B. Rendering a rectangle on a page

A rectangle will be represented as a model with properties for:

  1. width and height
  2. color
  3. position
var RectangleModel = function(data) {
    this.color = data.color;
    this.height = data.height;
    this.width = data.width;
    this.position = data.position;

    return this;
};

RectangleModel.prototype.get = function(property) {
   return this[property];
};

RectangleModel.prototype.set = function(property, value) {
    this[property] = value;
};

 

The view will have the responsibility for rendering a rectangle model

var RectangleView = function(model) {
    this.model = model;
    this.el = document.getElementById("rectangle");

    return this;
};

RectangleView.prototype.setColor = function() {
    this.el.style.background = this.model.get("color");
};

RectangleView.prototype.setDimensions = function() {
    this.el.style.width = this.model.get('width');
    this.el.style.height = this.model.get('height');
};

RectangleView.prototype.setPosition = function() {
    this.el.style.x = this.model.get('position').x;
    this.el.style.y = this.model.get('position').y;
};

RectangleView.prototype.render = function() {
    this.setPosition();
    this.setDimensions();
    this.setColor();
};

The controller will instantiate the view & the model and will load the view into the page.

var RectangleController = function() {
    return this;
};

RectangleController.prototype.loadView = function() {
    var model = new RectangleModel({
            color: 'red',
            height: 200,
            width: 300,
            position: {
                x : 10,
                y : 10
            }
    });

    var view = new RectangleView(model);

    return view.render();
};

A bootstrapper will instantiate the controller and call the loadView method.

var controller = new RectangleController();
controller.loadView();

View demo

C. Todo application (addition of events)

I will try to explain MVC in a Todo application with the addition of events this time:-) In this simplified Todo application user types a todo in an input field and after pressing enter, result is displayed underneath.

/**
  * View that abstracts away the browser's DOM
  */
function View() {
    this.$newTodo = document.getElementById('new-todo');
    this.$todoList = document.getElementById('todo-list');
}

/**
  * Takes a todo application event and registers the handler
  *
  * @param {string} event The event name
  * @param {function} handler The handler
  */
View.prototype.bind = function(event, handler) {
    var that = this;
    if(event === 'newTodo') {
        this.$newTodo.addEventListener('change', function() {
            handler(that.$newTodo.value);
        });
    }
};
/**
  * Renders the given command with the parameter
  *
  * @param {string} viewCmd The view command
  * @param {string} parameter The parameter
  */
View.prototype.render = function(viewCmd, parameter) {
    var that = this;
    var viewCommands = {
        clearNewTodo: function() {
            that.$newTodo.value = '';
        },
        showTodo: function() {
            var template = {{title}} that.$todoList.innerHTML = template.replace('{{title}}', parameter); } }; viewCommands[viewCmd](); };
/**
  * Takes a model and view and acts as the controller between them
  *
  * @constructor
  * @param {object} model The model instance
  * @param {object} view  The view instance
  */
function Controller(model, view) {
    var that = this;
    this.model = model;
    this.view = view;

    this.view.bind('newTodo', function(title) {
        that.addItem(title);
    });
}

/**
  * An event to fire whenever you want to add an item. Simply pass in the event
  * object and it'll handle the DOM insertion and setting the model.
  */
Controller.prototype.addItem = function(title) {
    if(title.trim() === '') {
        return;
    }

    this.model.setTitle(title);
    this.showTodo(title);
    this.view.render('clearNewTodo');
};

/**
  * Renders the view and displays the last inserted todo item
  */
Controller.prototype.showTodo = function() {
    var data = this.model.getTitle();
    this.view.render('showTodo', data);
};

/**
  * Creates a new Model instance
  */
function Model() {

}

/**
  * Sets title
  *
  * @param {string} title The title
  */
Model.prototype.setTitle = function(title) {
    this.title = title.trim();
};

/**
  * Gets title
  */
Model.prototype.getTitle = function() {
    return this.title;
};

function Todo() {
    this.model = new Model();
    this.view = new View();
    this.controller = new Controller(this.model, this.view);
}
function Todo() {
    this.model = new Model();
    this.view = new View();
    this.controller = new Controller(this.model, this.view);
}

var todo = new Todo();

View Demo

General flow

Control flow generally works as follows:

  1. The user interacts with the user interface in some way (e.g. presses a button).
  2. A controller handles the input event from the user interface, often via a registered handler or callback.
  3. The controller notifies the model of the user action, possibly resulting in a change in the model’s state. (e.g. controller updates user’s shopping cart).
  4. A view uses the model (indirectly) to generate an appropriate user interface (e.g. the view produces a screen listing the shopping cart contents). The view gets its own data from the model. The model has no direct knowledge of the view.
  5. The user interface waits for further user interactions, which begins a new cycle.