AJAX MVC (so to speak)

September 19th, 2006. Tagged: Ajax, JavaScript, mvc, yui

This is sort of a framework thing to create AJAX applications, based on the MVC design pattern. Yep, I have a lot of buzzwords here, I admit, but this shouldn't be taken too seriously. I was doing a bunch of small projects lately and I found myself using something like this little framework, without even thinking about it. Then I thought about it and I found that the scripts and the organization of them may resamble MVC a bit. So how does MVC fit when you mix things like thin and fatter client, HTML, JavaScript, XMLHttpRequest, PHP and CSS?

Usual AJAX app flow

What usually happens in an AJAX application is:

  1. you have an HTML page, styled with CSS
  2. you click on something
  3. JS sends request to the server (to a PHP script)
  4. JS updates the original HTML page

Mapping to the MVC pattern

OK, so what part of this process can be associated with a View, or a Model or a Controller? The Model is easy, it's the business logic, writing to a database and so on. This is the PHP script. The View? Obviously this is the HTML page and the CSS. But I'd like to think also about the JS that updates the page as part of the View. I mean it makes sense, it's updating the presentation part. Sometimes you even use innerHTML in the JS, but even if you use DOM, it becomes part of the HTML anyway. How about the Controller? Well, we have two controllers here. One that is on the server side, a PHP script that receives requests and "asks" the Model for the response. The other controller is on the client side, this is the JavaScript that decides what happens on a click of a button and sends an appropriate AJAX request to the PHP controller. Therefore I would consider any behavioural JS as part of the Controller, including attaching events as well as sending HTTP requests.

Here's an illustration:
AJAX MVC

In action (example)

I went ahead and implemented a very simple application to prove the concept. It's just a blank styled HTML page with a button. The HTML page includes two JavaScripts responsible for behaviours (Controller) and page updates (View). The page also includes a few unrelated helper javascripts, in my case I'm using the YUI library. The JS Controller attaches an event to the button. Then when you click the button, the JS Controller sends a request to the PHP controller. The PHP controller (just a simple switch) figures out what was requested and calls the appropriate object of the business model. In my simplistic case, the abovementioned "model object" is just a simple function, but this can be easily built upon. The Model returns (JSON-encoded) response, in this case it's a list of installed PHP extensions. Now the response is received by the View JS and it updates the page. After that the View calls another function from the JS controller that attaches new events to the new content. (Yep, a little glitch here, maybe it would have been better if the Model's response is handled by the JS controller which in turn calls the JS view updater, but anyway this is easy to fix)

Directory layout

Here's the directory structure:
AJAX MVC dir

One might argue that it's better if you don't mix .js, .css and .php files in the same directory but the whole idea is open to interpretations anyway, it's just an illustration of the idea.

The code for the example

We get to the fun part, the actual implementation. So we start with a simple .html page, the initial part of the view.

This is index.html

<?xml version="1.1" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome</title>
  <link rel="stylesheet" href="../view/styles.css" type="text/css" media="all" title="Default styles" />
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/yahoo/yahoo-min.js"></script>
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/event/event-min.js"></script>
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/connection/connection-min.js"></script>
  <script language="javascript" type="text/javascript" src="../view/updates.js"></script>
  <script language="javascript" type="text/javascript" src="../controller/behaviours.js"></script>
</head>
<body>
 
  Welcome to my app!
  <br />
  <form action="" method="post">
    <input type="button" name="b" id="thebutton" value="I'm a button, click me!" />
  </form>
  <div id="content">&nbsp;</div>
 
</body>
</html>

As you can see, nothing special, simply including the CSS styles, the YUI "extras" and two other javascripts - one part of the View and one that is part of the Controller.

The Controller JS is responsible for attaching an event listener to the button.

This is an excerpt from the behaviours.js

// the behaviour class
var behaviours = {
 
    phpcontroller: "../controller/switch.php?request=",
 
    // more behaviour.methods....
}
 
 
// initial page load, attach onload event(s)
YAHOO.util.Event.addListener(
    'thebutton', 'click', behaviours.theButtonClick);

Now when the user clicks the button, the method behaviours.theButtonClick() is executed. It fires a request to the PHP controller switch and says that the request type is "loadSomething":

theButtonClick: function(e) {
  alert('Ouch! \n\nOK, I\'ll make a request for ya, buddy!');
  YAHOO.util.Connect.asyncRequest (
      'GET',
      behaviours.phpcontroller + 'loadSomething',
      {success: updates.writeContent}
  );
},

The PHP controller (controller/switch.php) receives the request, does a simple switch to validate the request type and then calls the appropriate (in my case just a simple) function from the business model. Here's the full switch.php code:

<?php
// is this a request?
if (empty($_GET['request'])) {
  die();
}
// get the business logic
include_once '../model/business.php';
 
// figure out the request
// and call the business logic object
switch ($_GET['request']) 
{
  case 'loadSomething':
    echo loadSomething();
    break;
  case 'loadSomeMore': // not used, example
    echo loadSomeMore();
    break;
}
?>

The function loadSomething() from the PHP model gets a list of installed PHP extensions, encodes them into JSON and sends them back. This is a full listing of the ../model/business.php

<?php
function loadSomething() {
  $extensions = get_loaded_extensions();
  return '["'. implode('","', $extensions) . '"]'; 
}
?>

If you go back and look at the AJAX request, you'll see that on success, I call the updates.writeContent() method. The ../view/updates.js script contains stuff that updates the HTML of the original page, so its place is in the View part of the app. writeContent simply creates an HTML table with the results (the list of PHP extensions). Then I wanted to attach event listeners to this table just to change color, but it can be more than that. Attaching events is a job for the JS Controller, therefore a method of its class is called. Here's a full listing of updates.js:

var updates = {
 
  writeContent: function (xmlhttp) {
    if (!xmlhttp.responseText) {
      alert("I got nothing from the server");
    }
    var data = eval(xmlhttp.responseText);
    var write_to = document.getElementById('content');
    write_to.innerHTML = ''; // yeah, I know
    
    var html2dom_root = write_to;
    var table = document.createElement("table");
    var table_1_tbody = document.createElement("tbody");
    for (var i in data) {
      table_1_tbody_2_tr = document.createElement("tr");
      table_1_tbody_2_tr_1_td = document.createElement("td");
      num = 1 + parseInt(i);
      table_1_tbody_2_tr_1_td_1_text = document.createTextNode(num);
      table_1_tbody_2_tr_1_td.appendChild(table_1_tbody_2_tr_1_td_1_text);
      table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_1_td);
      table_1_tbody_2_tr_2_td = document.createElement("td");
      table_1_tbody_2_tr_2_td_1_text = document.createTextNode(data[i]);
      table_1_tbody_2_tr_2_td.appendChild(table_1_tbody_2_tr_2_td_1_text);
      table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_2_td);
      table_1_tbody.appendChild(table_1_tbody_2_tr);
    }
    table.appendChild(table_1_tbody);
    html2dom_root.appendChild(table);
    
    behaviours.updateTableBehaviour();
  }
}

(BTW, for the DOM part I'm used the help from my little tool html2dom to make my life a bit easier)

And finally here's the rest of the JS controller (behaviours.js), the method behaviours.updateTableBehaviour() that adds an event listener to the new table and the trClick() that handles clicks on this table. On click, it justs changes the color of the underlying row.

  trClick: function (e) {
    var target = (e.srcElement) ? 
      e.srcElement.parentNode : e.target.parentNode;
    if (target.tagName == 'TR') {
      if (target.className == 'tr-on') {
        target.className = '';
      } else {
        target.className = 'tr-on';
      }
    }
  },
  
  updateTableBehaviour: function () {
    var el = document.getElementById('content').firstChild;
    YAHOO.util.Event.addListener(
      el, 'click', behaviours.trClick);
  }

Demo and downloads

  • Demo - the live example
  • Zipped demo - all the source code for the example
  • Template - the source code for the example but with the example part commented, so you can use it as a template for your next AJAX project. The only thing you need to do is to drop the YUI in the _extras/yui folder.

Thank you for reading, any comments welcome!

Tell your friends about this post: Facebook, Twitter, Google+

29 Responses

  1. [...] http://www.phpied.com/ajax-mvc/ [...]

  2. [...] Ever feel like, when you’re coing up that next great Ajax application, that you’re doing the same things over and over again? Like there has to be something better out there to help you make development of common functionality a lighter and easier task? MVC (Model/View/Controller) just might be what you’re looking for, and in this new posting on PHPied.com, they show you the basics of creating your own Ajax MVC framework. This is sort of a framework thing to create AJAX applications, based on the MVC design pattern. Yep, I have a lot of buzzwords here, I admit, but this shouldn’t be taken too seriously. I was doing a bunch of small projects lately and I found myself using something like this little framework, without even thinking about it. Then I thought about it and I found that the scripts and the organization of them may resamble MVC a bit. So how does MVC fit when you mix things like thin and fatter client, HTML, JavaScript, XMLHttpRequest, PHP and CSS? [...]

  3. PHPied.com: AJAX MVC (so to speak)…

  4. Interesting article and there is definitley a need to extend MVC off of the server. However, don’t you think that there is at least some model on the client side? The way I see it is that the view and controllers on the client side interact with a client side model. That client side model then handles the data retrieving and sending. This way you can more easily build caching and buffering into your ajax system. It also means the client side V and C don’t need to know about the server and it can change without effecting them.

  5. Thanks for the comment Paul! I’ll need some time to digest that client Model ;)

  6. [...] Ever feel like, when you’re coing up that next great Ajax application, that you’re doing the same things over and over again? Like there has to be something better out there to help you make development of common functionality a lighter and easier task? MVC (Model/View/Controller) just might be what you’re looking for, and in this new posting on PHPied.com, they show you the basics of creating your own Ajax MVC framework. [...]

  7. Hi, just wanted to say thanks for the great logical explanation on how Ajax can be represented in the MVC pattern.

  8. When it comes to HTML/CSS/JavaScript, MVC is known by another name – Presentation, Structure and Behavior. Presentation is the CSS, Structure is (X)HTML and Behavior is JS. Granted, it is different from MVC – but I always equate the two like this…
    Model = Structure
    View = Presentation
    Controller = Behavior

  9. I agree with Binny V A that Structure/Presentation/Behaviour is more appropierate for the clientside. How about renaminging it into SPB design pattern for the clientside altogether and make it distintly separate from the backend MVC? That way the job of designing the app could be devided into GUI and Enterprise logic, allowing tweo different peers working together without having to spend time interacting all the time (or be unavoidably done within the same team, whereas it be done faster by peers with different specialties)

    Just my 2 cents… :-)

  10. [...] the solution could involve moving the MVC to different level. Check this interesting article for PHP developers. [...]

  11. Stoyan – the only thing I understand on this whole page is the “russian dating” spam right above me. I’ll have to return and print this out and study. It looks wonderfully geeky!

  12. Well, it’s not too special, but I like it myself ;)

    (Russian dating spam deleted. I got soo much spam comments, I deleted the spam about 20 hours ago and now I had 258 comments held for moderation and probably 50 that made it through the filters. Damn!)

  13. [...] Buscando, buscando, he encontrado éste artículo de phpied.com. La solución que propone es interesante, pero como él mismo dice es una mera prueba de concepto. [...]

  14. While your solution for outputting the resultset may seem simple, here’s a far more elegant and simplistic solution:

    
    var str = "<table>";
    
    for (var i in data)
    {
        str += "<tr><td>" + data[i] + "</td></tr>";
    }
    
    str += "</tr>";
    
    var contentPanel = document.getElementById('content');
    contentPanel.innerHTML = str.toString();
    

    If your business module were to return an actual result set from the database, you can easily retrieve the row’s column value by doing this: data[i].columnName.

    Here’s a practical example:

    /*
    OUTPUT OF TABLE
    ——————————–
    id | last name | first name |
    ——————————–
    1 | smith | john
    2 | sisko | benjamin
    3 | janeway | katherine
    */
    var str = "<table><tr><td>id</td><td>last name</td><td>first name</td></tr>";
    
    for (var i in data)
    {
        str += "<tr><td>" + data[i].id + "</td><td>" + data[i].lastName + "</td><td>" + data[i].firstName + "</td></tr>";
    }
    
    str += "</table>";
    
    var contentPanel = document.getElementById('content');
    contentPanel.innerHTML = str.toString();
    
  15. [...] Boris of http://www.ajaxplanet.ru/ has translated my article on the little AJAX/MVC framework I came up with, this is trully flattering, thanks a lot! [...]

  16. [...] Ajaxian vient de relater un article de PHPied sur la mise en application du modèle MVC avec Ajax. [...]

  17. First of all thanks for the example it clears things up for me about how others are working with MVC. My criticism of this particular methodology would be that all of your ‘module parts’ are abstract. How do you manage them as one piece should you want to reuse the whole module? While I agree with the core part of the concept I am wondering about how difficult it would be to manage.

    I think my approach is more of a “MVC Fusebox”. In my scenario you operate on with the AJAX and “business” controller as an AJAX engine. Then when you drop in a module and make a menu reference it is live. I would be interested to hear your thoughts on this approach.

  18. Hi,

    Nice concepts you have here! Almost a year after your posting, there’s a paper on using AJAX to implement the business controller:

    http://wisdomofganesh.blogspot.com/2007/10/life-above-service-tier.html

    And the corresponding discussion at The Server Side:

    http://www.theserverside.com/news/thread.tss?thread_id=47213

  19. We’re in the process of launching a true JavaScript MVC framework called … what else but JavaScriptMVC ( http://javascriptmvc.com ). It has everything you’d expect in an MVC framework:

    Include – can include and compress files cross domain.

    Model – Integrated Jester REST library.

    Controller – Best in class event delegation library. Function names are combination css selectors and event names.

    View – Integrated EJS library (embeddedjs.com)

    And, we’ve got things like gears, history, and remote scripting integrated as well.

  20. Hi. Congratulations for your article very useful. But I have a question, Working with Object Oriented Programming, it is possible to retrieve objects from the server. Which is the best way to achieve (An example if possible).

  21. The way I see it is that the view and controllers on the client side interact with a client side model. That client side model then handles the data retrieving and sending.

  22. This is not really a framework. Typically, you don’t unzip a framework and program into it. In fact, you never do — that would be called a template; indeed, this is an “application template”. Meanwhile, it’s not really an MVC either, an MVC is an application in which the model is consumable by a view (note: models in that context are typically objects…data structures which have behavior) and in your case, the model is … a function?

    Also I should mention, that there are better ways to deal with dynamic dispatch than a big switch statement — in fact, that’s probably the worst way. A dispatch table would be more appropriate, since PHP doesn’t particularly have function references (atleast, last I checked…it’s been some years, probably does now) you could simply use dynamic method-name invocation to simulate a dispatch table ($object->$method()). But in an ideal scenario, and in a framework for that matter, usually your controller is data driven, not a big switch statement you have to add another case to for each new bit of functionality (that doesn’t sound very maintenance friendly).

  23. Scott, I think you’re quibbling over implementation details there… the point his post was trying to make it that you can fit AJAX into MVC, and to throw out a brief example for the sake of discussion than provide a definitive framework other people would use to build apps in.

    I’m currently working on the same issue and it was nice to get some ideas from Google before I start coding. Thanks for the article.

  24. [...] ideas interesantes, les invito a leer el articulo completo desde phpied.com … Link al post http://www.phpied.com/ajax-mvc/ Link al post en Castellano – (via Google translate) [...]

  25. I know this post has been written long ago, but I happened to be researching about architectural patterns and have found that there are diverse approaches (MVA, MVP, and 2 layers MVC). Have to say, that I like how you explain it but mixing js with html, or js with php is not so well separated, as the MVC fundamentals advocate.

    I like the Presentation Model pattern (also known as Application pattern) but will scheme the others approaches too.

    MVA:

    http://blog.palantirtech.com/2009/04/20/model-view-adapter/

    Model Adapter View
    eg: PHP PHP, JS HTML, CSS

    Presentation Model

    http://canoo.com/blog/2008/02/01/the-world-needs-more-models/
    http://martinfowler.com/eaaDev/PresentationModel.html

    Model Controller Presentation Model View
    eg: PHP PHP JS HTML, CSS

    MVC 2 layers:

    Client: Model Controller View && Server Model Controller View
    eg: PHP PHP XML, JASON JS JS HTML, XML

    I know these patterns say almost the same, but hey just pick one, try it and look which one fits you better. For my purposes I choosed the Model Presenter with an AJAX approach, as it is based on an desktop application and therefore it resembles AJAX objective… bring the application features to a web platform.

  26. Install ZEUS Bot FREE – hack bank acc. http://www.cyberlocos.net Ver foro – Malwares – Troyanos – Crimewarez – Botnets

  27. AJAX MVC (so to speak) / Stoyan’s phpied.com…

    Thank you for submitting this cool story – Trackback from Blue Ray Plus – Latest Technology News…

  28. , , , ,
    . --, 14, .

  29. I enjoy you because of all your valuable effort on this web site. Betty really loves engaging in investigation and it’s easy to understand why. All of us know all relating to the compelling medium you render very important thoughts via the blog and therefore invigorate contribution from some other people on this subject matter while our own simple princess is truly being taught so much. Have fun with the rest of the year. Your performing a fantastic job.

Leave a Reply