• Home
  • blog
  • The MVC Design Pattern in Vanilla JavaScript

The MVC Design Pattern in Vanilla JavaScript

Design patterns often get incorporated into popular frameworks. The Model-View-Controller (MVC) design pattern, for example, is one that is ubiquitous. In JavaScript, it is hard to decouple the framework from the design pattern. Oftentimes, a particular framework will come with its own interpretation of this design pattern. Frameworks come with opinions and each one forces you to think in a certain way.

Modern frameworks dictate what the concrete implementation of the MVC pattern looks like. This is confusing when all interpretations are different, which adds noise and chaos. When any code base adopts more than one framework it creates a frustrating mess. The question in my mind is, is there a better way?

The MVC pattern is good for client-side frameworks, but modern frameworks change. What is modern today is subject to the passing of time and withers away. In this take, I’d like to explore alternatives and see where a little discipline takes us.

By itself, the MVC pattern dates back more than a few of decades. This makes it a good design pattern to invest your programming skills in. The MVC pattern is a design pattern that can stand on its own. The question is, how far can this take us?

Wait, Is This Yet Another Framework?

First, I’d like to dispel this common myth: a design pattern is not a framework. A design pattern is a disciplined approach to solving a code problem. There is a level of skill necessary and places the responsibility on the programmer. A design pattern separates concerns and promotes clean code.

A framework is different since it does not have to adhere to any design pattern. A way to tell a framework from a pattern is to look for the Hollywood principle. The Hollywood principle is, “don’t call us, we’ll call you.” Anytime there is a dependency that dictates when you use it, it is a framework. A framework is a lot like Hollywood in that you don’t get a say on what to do or how to do it. In fact, developers are like actors because they follow the script when asked to act.

There are good reasons to avoid client-side frameworks:

  • Frameworks add complexity and risk to your solution
  • You experience dependency lock-in, which leads to unmaintainable code
  • As new fad frameworks emerge, it is difficult to rewrite existing legacy code

The MVC Pattern

The MVC design pattern emerged from the Xerox Smalltalk research project in the 1970s and into the 80s. It is a pattern that has stood the test of time for front-end graphical user interfaces. The pattern came from desktop applications but has proven to be effective for web apps too.

At its crux, the MVC design pattern is about a clean cut separation of concerns. The idea is to make the solution intelligible and inviting. Any fellow programmer looking to make specific changes can find the right spot with ease.

A Demo of Penguins

Penguins! Cute and cuddly, some of the furriest creatures on the planet. So cute, in fact, there are 17 different kinds of penguins which don’t all live in Antarctic conditions.

Time for a demo of penguins! I’ll show a deck showing several species on a single page. For this, I’d like to use the MVC design pattern and a little discipline. I’ll use the extreme programming methodology to solve the problem at hand with unit tests and no nonsense. At the end, you should be able to flip through a few penguins each with its own data and profile picture.

By the end of this example, you should have learned enough to use the MVC design pattern in plain JavaScript. The pattern itself is super testable so expect good unit tests.

I’ll stick to ES5 for this demo for cross-browser compatibility reasons. It makes sense to use proven language features with this perennial design pattern.

Are you ready? Let’s find out.

The skeleton

The demo will consist of three main parts: controller, view, and model. Each with its own concern and problem that it needs to solve.

A visual of what this looks like is below:

Demo of Penguins Visual

The PenguinController handles events and is the mediator between the view and model. It works out what happens when the user performs an action (for example, clicking on a button or pressing a key). Client-side specific logic can go in the controller. In a bigger system, where there is a lot going on, you can break it out into modules. The controller is the entry point for events and the only mediator between the view and data.

The PenguinView cares about the DOM. The DOM is the browser API you use to make HTML manipulations. In MVC, no other part cares about changing the DOM except for the view. The view can attach user events but leaves event handling concerns to the controller. The view’s prime directive is to change the state of what the user sees on the screen. For this demo, the view will do the DOM manipulations in plain JavaScript.

The PenguinModel cares about data. In client-side JavaScript, this means Ajax. One advantage of the MVC pattern is you now have a single place for server-side Ajax calls. This makes it inviting for fellow programmers who are not familiar with the solution. The model in this design pattern cares only about JSON or objects that come from the server.

One anti-pattern is to violate this intrinsic separation of concerns. The model, for example, must not care about HTML. The view must not care about Ajax. The controller must serve as the mediator without worrying about implementation details.

What I find with this pattern is developers start with good intentions but leak concerns. It is tempting to turn everything into a web component and end up with mush. The emphasis gets put on features and user facing concerns. But, feature concerns are not the same as functional concerns.

In programming, what I like is having a clean cut separation of functional concerns. Each separate programming problem gets a consistent way of solving it. This makes it a lot more intelligible when you read the code. The idea is to write code that is inviting so others can make positive contributions too.

It would not be much of a demo without a real live example you can see and touch. So, without further ado, below is a CodePen showcasing the demo of penguins:

See the Pen A Demo of Penguins by SitePoint (@SitePoint) on CodePen.

Enough talk, time for some code.

The controller

The view and model are two components used by the controller. The controller has in its constructor all the components it needs to do the job:

var PenguinController = function PenguinController(penguinView, penguinModel) {
  this.penguinView = penguinView;
  this.penguinModel = penguinModel;

The constructor uses inversion of control and injects modules in this way. This pattern enables you to inject any component that meets the high-level contract. Think of it as a nice way to abstract code from implementation details. This pattern empowers you to write clean code in plain JavaScript.

Then, user events get wired up and handled in this way:

PenguinController.prototype.initialize = function initialize() {
  this.penguinView.onClickGetPenguin = this.onClickGetPenguin.bind(this);

PenguinController.prototype.onClickGetPenguin = function onClickGetPenguin(e) {
  var target = e.currentTarget;
  var index = parseInt(target.dataset.penguinIndex, 10);

  this.penguinModel.getPenguin(index, this.showPenguin.bind(this));

Continue reading %The MVC Design Pattern in Vanilla JavaScript%