MVC Pattern

This lesson discusses the MVC pattern in detail using a coding example.

What is the MVC pattern?

The MVC pattern stands for Model-View-Controller pattern. It is an architectural pattern that is used to organize the code of your application. It consists of three components:

  • Model:

    The model component manages the data that the application may require.

  • View:

    The view is used for the visual representation of the current model. It renders data on the user’s side.

  • Controller:

    The controller connects the model and the view components.

The model is independent of the view; meaning, it is not concerned with the user interface and how the information is displayed on the user side. The view, on the other hand, is an observer of the model. Whenever the model gets modified (data is updated) it notifies its observer (the view) which then reacts accordingly.

As mentioned view is the visual representation of the model. Whenever it is notified of a change in the model, the view updates accordingly. As the view layer is what the users get to see, this is also the layer they get to interact with such as editing or updating attribute values.

The controller is the connection between the model and the view. The two do not interact with each other directly. The controller takes input from the user such as a click or keypress which updates the view side and then updates the model accordingly. It can sometimes update the view directly as well.

Example #

Press + to interact
class EmployeeModel
{
constructor(name, designation, id){
this.name = name;
this.designation = designation;
this.id = id;
}
getDesignation()
{
return this.designation
}
getID(){
return this.id
}
getName()
{
return this.name
}
}
class EmployeeView
{
constructor(){
this.controller = null;
}
registerWith(controller) {
this.controller = controller;
this.controller.addView(this);
}
printEmployeeInfo( name, designation, id)
{
console.log(`Employee info:\nName is: ${name}\nID is: ${id}\nDesignation is: ${designation}`);
}
hire(name, designation) {
this.controller.hire(name, designation);
}
editName(id,name){
this.controller.setEmployeeName(id,name);
}
}
class EmployeeController
{
constructor(){
this.model = null;
this.view = null;
this.empList = [];
}
addView(view) {
this.view = view;
}
addModel(model) {
this.model = model;
}
setEmployeeName(id,name){
if(this.empList[id]){
this.empList[id].name = name;
this.updateView();
}else{
console.log("Incorrect id");
}
}
updateView()
{
console.log("List of employees:")
for( let i in this.empList)
this.view.printEmployeeInfo(this.empList[i].getName(), this.empList[i].getDesignation(), this.empList[i].getID());
console.log("\n");
}
hire(name, designation) {
this.empList.push(new EmployeeModel(name, designation, this.empList.length));
this.updateView();
}
}
var view = new EmployeeView();
var controller = new EmployeeController();
view.registerWith(controller);
console.log("Hiring a new employee Rachel");
view.hire("Rachel", "Team Lead");
console.log("Hiring a new employee Jack");
view.hire("Jack", "Software Engineer");
console.log("Updating the name of employee with id 0");
view.editName(0,"Monica");
console.log("Updating the name of an employee with id 7");
view.editName(7,"Joey");

Explanation

Given above is a basic MVC pattern example. This program simply displays the information of the employees hired. As discussed, it is divided into three components:

  • The employee object is represented by the model EmployeeModel.

  • The employee’s information is displayed by the view component EmployeeView.

  • The model and view components are connected through the controller EmployeeController.

Let’s take a look at each component one-by-one.

  • EmployeeModel

    class EmployeeModel 
    { 
      constructor(name, designation, id){
          this.name = name;
          this.designation = designation;
          this.id = id;
      }
    
      getDesignation()  
      { 
        return this.designation
      }
    
      getID()
      {
        return this.id
      }
    
      getName()  
      { 
        return this.name
      } 
    } 
    

    The EmployeeModel presents an employee object which has the following properties: the name, the designation, and the id of the current employee. It also has get functions for these properties to retrieve the values of these properties.

  • EmployeeView

    class EmployeeView  
    {
      constructor(){
         this.controller = null;
       }
     //code...
    } 
    

    The view is responsible for displaying the data, that is, the employee information on the user interface. It must show the updated information if a change occurs in the data in the model or if a user makes an edit in the view when interacting with the interface.

    As discussed, the controller acts as the mediator between the model and the view. Hence, for the controller to be able to communicate with the view, we initialize the current view for the controller by first setting the controller property and then adding the view to it:

    registerWith(controller) {
      this.controller = controller;
      this.controller.addView(this);
    }
    

    Next, let’s look at the scenario when a user makes an edit in the view. In this case, let’s assume the HR fills the information of an employee (name & designation) and invokes the hire function in view (you can think of it as a button at the end of the form). So now that there has been an edit in the view, the controller will register that user action and make changes on the model side accordingly.

    hire(name, designation) {
          this.controller.hire(name, designation);
    }
    

    We’ll discuss the changes the controller makes in detail, later on. For now, all you need to know is that as a result of the user action on the view side, the controller invoked its own hire function to make updates at the model side.

    Another scenario is when the data in the model changes and the view updates itself accordingly. For example, HR changes the name of an existing employee. This change in the model will need to be reflected on the view side. Here again, the controller will act as the mediator between the two:

     editName(id,name){
       this.controller.setEmployeeName(id,name);       
    }
    

    We’ll look into how the updated information of an employee is communicated and reflected on the view side later on.

    Lastly, since the view needs to display the information, it also has a print function that displays the name, id, and designation of the employee.

    printEmployeeInfo( name, designation, id) 
    { 
      console.log(`Employee info:\nName is: ${name}\nID is: ${id}\nDesignation is: ${designation}`); 
    } 
    
  • EmployeeContoller

    class EmployeeController  
    { 
      constructor(){
          this.model = null;
          this.view = null;
          this.empList = [];
      }
      
      addView(view) {
          this.view = view;
      }
      addModel(model) {
          this.model = model;
      }
      //code...
    }  
    

    The controller has the methods addView and addModel to initialize the model and the view components. It also initializes the property empList, which stores the list of all employee model objects.

    The controller has a hire function of its own that it calls when the HR person calls the hire function on the view side.

    hire(name, designation) {
          this.empList.push(new EmployeeModel(name, designation, this.empList.length));
          this.updateView();
    }
    

    The function creates a new instance of the EmployeeModel using the name and designation of the person the HR wants to hire. It then adds the new employee into the empList. Now that a new employee has been added to the list, the controller updates the view by making a call to the updateView function.

    Let’s look at how the updateView function is defined:

    updateView() 
    {
      console.log("List of employees:")
          
     for( let i in this.empList)      
           this.view.printEmployeeInfo(this.empList[i].getName(), this.empList[i].getDesignation(), this.empList[i].getID()); 
      console.log("\n");
    }    
    

    The function iterates through the list of employees and calls the printEmployeeInfo function in view for each employee.

    Next, the controller also has a setEmployeeName function:

    setEmployeeName(id,name){
       if(this.empList[id]){
         this.empList[id].name = name;
         this.updateView();
        }else{
           console.log("Incorrect id");
        } 
    } 
    

    Whenever data (name) in the employee model is to be updated by the HR, the setEmployeeName function in the controller is invoked. It finds the id of the employee whose information is to be changed. If the employee exists, it accesses that employee model and changes its name property. When the data in the model changes, the view is also updated by invoking the updateView function. If the wrong id is accessed, the message Incorrect id is displayed.

When to use the MVC pattern? #

You can use this pattern:

  • If you want improved application organization in your application.

  • If you want faster development as developers can work on different components of the application simultaneously.

  • If you want to develop an application that loads fast as MVC supports asynchronous technique.

  • If you want multiple views for the model.

  • If you want to increase the scalability of the application as modification in separate components is easier.


Now that you know what the MVC pattern is, it’s time to implement it!