Sorting through long and cluttered JavaScript code with MVP

JQuery is a wonderful tool for JavaScripters and it’s been around for years, showing its true power and simplicity. But even jQuery falls short of solutions when the web site/application grows in size and complexity.

After writing a lot of JavaScript code on a web application, it becomes more obvious that the direct way of doing it is not the right way and ends up having code no one understands anymore.

So how to get rid of the JavaScript clutter? Enter MVP!

Model View Presenter

Actually it’s all about separation of concerns. The problem with most code is it mixes 3 aspects:

  1. AJAX calls
  2. DOM manipulation
  3. Event handling

We can call them the Model, the View and the Presenter and instead of putting them together in one place, we can define separate objects for each.

Let’s see how the code may look like on a page that performs an async search.

The Model

var model = {
  searchWebsite: function(searchQuery, handlers) {
    $.ajax({
      url: "/search",
      type: "POST",
      data: "q="+searchQuery,
      success: handlers.success,
      error: handlers.error
    });
  }
};

This guy is only responsible for sending the search query to the server, to the right URL and using the right method (POST). He will not interpret the response to populate the page with the results, for example. That’s not his problem. He only manages server calls.

The View

The View, on the other hand, he knows about how things are arranged on the page. He’s really good at finding stuff in the DOM tree, moving things around, changing styles and so on. In our example, he’ll be responsible for installing a handler on the search button, providing the search query and, later on, putting the results where they belong.

var view = {
  installSearchHandler: function(searchHandler) {
    $("#searchButton").click(function () {
      var searchQuery = $("#searchQuery").val();
      searchHandler.call(this, searchQuery);
    });
  },

  showSearchResults: function(searchResults) {
    for (aResult : searchResults) {
      // create a DOM node and show the aResult in it
      $("#searchResults").append('<p>'+aResult.title+'</p>');
    }
  },

  showSearchError: function(error) {
    $("errorDiv").show();
    $("#errorDiv #errorMessage").html(error);
  }
};

The Presenter

This guy is responsible for putting things together, he’s the middle man, deciding the flow of the page. The Presenter will install the listeners into the View and send requests to the Model to retrieve or send data from and to the server. An important aspect of the Presenter is that he’s aware of the other 2.

var presenter = {
  init: function() { // start from here (page load)
    view.installSearchHandler(this.search);
  },

  search: function(searchQuery) {
    model.searchWebsite(searchQuery, {
      success: function(data) {
        view.showSearchResults(data.searchResults);
      },
      error: function(data) {
        view.showSearchError(data);
      }
    });
  }
};

Starting up this chain of objects

The presenter.init() is supposed to start up this whole deal, from there on, he’ll handle everything and delegate tasks to the view or model as appropriate. We can use jQuery document ready for this:

$(document).ready(function() {
    presenter.init();
});

And we’re done!

What’s the gain?

Now that we’ve implemented our search the MVP way, let’s take a moment and look at our accomplishment. Why did we do this? What is our gain? If that’s not obvious, let’s see how the code would have looked without structuring it the way we did:

$(document).ready(function() {
    $("#searchButton").click(function () {
      var searchQuery = $("#searchQuery").val();
      $.ajax({
        url: "/search",
        type: "POST",
        data: "q="+searchQuery,
        success: function(data) {
          for (aResult : data.searchResults) {
            // create a DOM node and show the aResult in it
            $("#searchResults").append('<p>'+aResult.title+'</p>');
          };
        },
        error: function(error) {
          $("errorDiv").show();
          $("#errorDiv #errorMessage").html(error);
        }
      });
    });
});

Everything is put together in one place, making it harder to read and understand what is all about.

On the other hand, if we look at our presenter, we understand immediately what the page is supposed to do: search by a searchQuery and, in case of success, showSearchResults, in case of error, showSearchError. You notice we used words from the code itself to explain what the page does – that’s because the code sounds more like an English language phrase than cryptic JS code.

In the real world out there, the code grows a lot more, as well as the clutter. Out there, this design will prove even more useful while our counter-example – even worse.

6 thoughts on “Sorting through long and cluttered JavaScript code with MVP

  1. henri

    Great article, thanks!

    Do you think it’s smart to create several models, views and presenters as the web application and amount of Javascript code grows? For example searchModel, searchView, and searchPresenter would handle only things associated with search. And for other modules there would be own models, views and presenters.

    1. The Neovibrant

      Henri,

      Thanks for the nice comment.

      I would definitely do that, it’s not a good idea to have a huge presenter for the entire web application. I would go on and create one per page or even more if the page had more aspects, like you mentioned the search aspect. And depending on the case, if anything else made more sense, I would use that type of separation.

      The cool thing is that there’s nothing to prevent various presenters interacting between themselves ;)

      1. henri

        Ok thanks!

        By the way, have you ever used backbone.js? I researched some more about Javascript frameworks and it seemed pretty popular. I’m starting to code my Javascript application soon and I’m now considering which strategy I should use for structuring the code. Your MVP example is very clear and understandable and I could start coding using it right away, but now I started to think if backbone.js or some other framework would offer more advantages?

        1. The Neovibrant

          Yes, backbone.js is great. I guess in the end it’s a matter of taste. Personally I prefer less boilerplate code and larger freedom of customization. On the other hand, this may not work as well for larger teams as it works for one or two developers as custom code may grow dirtier in time.

          There’s also the binding feature that may help when developing data centric websites, but may stand in your way if the website is more user centric.

Comments are closed.