Model-View-Controller in jQuery

Model-View-Controller in jQuery

Overview

If you haven’t read it already, be sure to check out this post where I talk more about the motivation for this tutorial.

This MVC setup is perfect if you want to build an application like Jotlet.net, 280Slides.com, or even Gmail. If you’re aiming to build a more traditional web app like BaseCamp, Flickr, or Digg, then this still might be a good resource. A good rule of thumb: If you web application has 1 page load, then this is a great setup! If your app has more than 1 page load, read on anyways and you still might be able to apply some of these principles.

The approach I outline below – as with all my tutorials – is server agnostic. I’ll be using PHP to power the demos, but you can easily use Ruby, Java, or even Lisp! 🙂

In the Wild

This MVC is being used at jotbook.net. Similar in principle to Workflowy, Jotbook lets you easily create new bulleted lists, share them, and edit them with anyone in realtime. The MVC is used to keep a full and update model of the list cached in the browser and automatically synchronized with the server using BAJAX. Check out the full source code at https://github.com/adamwulf/jotbook.

Goals

  1. Clean simple code
  2. Separate the logic of the view and the model
  3. Cache data on the client side – minimize AJAX calls
  4. Provide clean interface to data so disparate view objects can work together on same data model
  5. Maximize both model and view code reuse

The Tutorial

I’ve split this tutorial into multiple Phases. Each phase builds upon the previous, and each has its own demo and sample code that it walks through (and download!). So be sure to check them all out!

The first Phase sets up the foundation on which all the other’s will rely – so it’s a great place to start. Each next phase will add a bit of functionality onto the code from the previous phase.

  1. Phase 1: Loading data from the server
  2. Phase 2: Saving data to the server
  3. Phase 3: Managing Multiple and Relational Data Types (coming soon)
  4. Phase 4: Initializing the model with data (coming soon)
  5. Phase 5: Offline mode (coming soon)

50 thoughts on “Model-View-Controller in jQuery

  1. Hi Adam,

    I’ve actually been putting a heavily modified version of the model-view-controller pattern you describe above into practice in one of my current projects, as it is a rather large project and there is heavy use of AJAX throughout.

    I have actually gone for having a model, view and controller object extended from jquery, smiliarly to you have it but I then have requirement for separate pages and therefore separate models, views and controllers. For example, I have a page named “create”, so I have a createModel, a createView and a createController which are extensions of model, view, controller.

    Having been working with the pattern extensively for a couple of days, it seems to make the code very maintainable and clean, but I have come across one problem:

    Have you thought about how to handle sending parameters when requesting items? Some items require different values sent back depending on one or more parameters sent to them.

    I therefore modified the model to optionally accept parameters and go for POST rather than GET if indeed parameters are required. Seems fairly straightforward, right? Then there’s the problem of caching the same named item but for different combinations of parameters, and this is where I’ve come a little stuck. Caching seems a little redundant once you realise that if parameters are being sent then the response will be different a lot of the time.

    I think this idea needs to be extended a little. There needs to be some way of storing items along with the set of parameters which was sent with the request for the item, very crudely put would be something like cache[item][parameters] – but parameters can be any number of parameters and possibly arrays to send too, so this quickly falls over.

    This is rather long now! What are your thoughts on the matter?

    Joel

  2. Have you thought about how to handle sending parameters when requesting items? Some items require different values sent back depending on one or more parameters sent to them.

    Just to be clear – “caching data” in this MVC pattern isn’t referring to the browser caching AJAX requests automatically, as I think you’re describing here.

    To fix that, I always opt for the browser never to cache AJAX requests. This can be done by sending back no-cache headers from the server. A less graceful solution is to add a random parameter to the end of the query string: ajax.php?rand=[random number].

    The goal of the Model in the the client MVC is to cache data locally, so that we don’t have to AJAX as much in the first place. Asking the model for “Item number 5” shouldn’t even fire an AJAX call if that item is already cached in the Model.

    Keep your eyes out for Phase 2 of the tutorial – I hope to be finishing that up relatively soon. That phase will handle both loading and saving data to the server, and I think that will speak more directly to your app development.

    Cheers

  3. I’m talking about caching data within the model, in order to avoid multiple AJAX requests for the same item. But the problem arises when you’re requesting items where you’re sending parameters.

    For example, in most moderately sized web applications, you’re going to need more than just GET without any query string or POST parameters. This cropped up for me when using AJAX to retrieve a URL friendly title for a page, the “item” name may be “url_name”, but the value of the item will differ depending on the “full name” of the page for which that short URL is generated. So in this case you would request the “url_name” with a parameter “full_name”. So then retrieving “url_name” in the future returns the cached “url_name” which would not be the desired result, since the “full_name” may have changed.

    I hope you understand the problem I’m describing now.

  4. I’m talking about caching data within the model, in order to avoid multiple AJAX requests for the same item. But the problem arises when you’re requesting items where you’re sending parameters.

    Ah- I think I understand you now,

    In the tutorial as it’s outlined in Phase 1, items are only cached by their unique ID. So if we needed to also be able to ask the Model for items based on something other than their ID (some other parameters in your request), then the cache is no longer very useful. I think this what you’re getting at?

    The solution in this case ends up being much more application specific. It often ends up being useful to hash the data on much more than just the ID – maybe the created on date, maybe a user ID, in your case maybe “full name”. Then when asking the Model for data related to some other parameter, the Model can look up data in a 2nd or 3rd hashtable.

    Stay tuned for Phase 3 where I’ll be solving a similar problem and caching data on more than just an Id.

    Cheers

  5. Yep I think you’re with me now – and I had thought about a hashtable approach, I think that’s the only real solution to the problem. Whatever the solution, it needs to be as abstracted as possible, and there may be good reason for certain items to never be cached.

    I’ll be keeping tuned for the later phases, thanks again for opening my eyes to using the much used model-view-controller pattern client-side!

    I expect I will be developing my own version of this, so I will let you know if I come up with some method for caching items with additional data – I certainly think it is something which is necessary in order to make this truly usable.

  6. Hi Adam and Joel,
    Just googled onto this Ajax’ed MVC model. I’ve been looking at JavascriptMVC.com.
    ° I like your model involving Cache-V-C on the browser and MVC on the server. Would like to add that in some complex situations, you may need to synchronize data back to the server.
    ° I’m looking forward to implement this model and to put more intelligence on the browser to offload the server. There would be lots of security concerns (e.g. session info).

  7. good evening,
    my name is noor, i would like to inform that i have a project related to MVC and i need a help. so, can you help me in answering these two questions:
    1- Examples of MVC?
    2- What is a pattern within the context of software development?
    thank you alot and best regards,
    noor:)

  8. joel, i would love to see some code samples of how you extended the base model view and controller classes into more specific instances. thanks!

  9. hi there,

    I’m eager to read the phase3 and other upcoming sections…will they be posted soon?

    currently I’m working on a project using asp.net mvc with nHibernate spring and jQuery

    thx a lot

  10. @george

    I wish I could say that stage 3 was coming out soon, but i’m swamped with work 😛 It’s still on my radar for sure, but don’t hold your breath, heh

    glad you liked the read!

  11. This is great stuff! I feel the same need as you, I’m currently developping a new web 2.0 application and wanted to do things in the right away this time, to avoid the javascript messy management.

    You mentioned that the code is most suitable for those applications with only one page load, and I believe you’re saying that because of the client-side cache, right? (reloading would loose the cache and defeats the purpose). Have you ever considered to have an invisible frame (height=0) from where AJAX calls would be made and where the cache would be kept?

    This way your main screen could be reloaded and cache would be preserved. I have this arcthitecture implemented here where I work at, but we are still in the rock age (that is, not using jquery :-).

    For my personal project I’ll see if I can mix the two things: client-side jquery/json mvc and invisible frame caching.

    Good work!

  12. This has been inspiring, Adam.

    After playing and building upon this for a few days, I’ve taken this in an interesting direction.

    Are you aware that there’s nothing in these articles, and nothing I’ve built-upon the articles, that is inherently jQuery’ish at core?

    In other words, the jQuery.extend({}} method for creating Models, Views, and Controllers, isn’t required.

    I’ve now mapped the basic ideas onto an alternative base, described by our good friend here: http://is.gd/mED0

    This removes the tricky inheritance difficulties (and failings) inherent in jQuery.extend({}} and, as a result, I have Models, Views, and Controllers as subtypes of an MVCBase class and nicely partitioned lower subtypes for different types of Controllers and Views reflecting the different types interaction panes in this application.

    jQuery is still used throughout, and the MVC elements themselves use jQuery functionality extensively, just that they aren’t themselves jQuery objects.

    Stepping outside the jQuery paradigm for the MVC pieces is a nice breakthrough. Nothing is lost, and the ability to properly classify subtypes is much easier and more straightforward.

    A cool variant I’ve implemented is, using jQuery, a Controller can manage many Views, as you might see in a tabbed interface where each tab is driven by a separate business object but centrally managed by a Controller in a generic way.

    Another View, a basic one, serves to enable and disable tabs as a particular page goes in and out of edit mode. Similarly another simple View serves as an interface to enable and disable other navigation menus as the page goes into edit mode.

    Thanks for the inspiration. Those listeners are killer!

    **–** Steve

  13. @Steven

    really glad you liked all the walkthroughs!

    completely agree on the failings of $.extend and general inheritence problems in JavaScript, and the link you point to is a great resource for a competing way to define classes.

    I opted to define classes in one giant function() call, instead of using the Class.prototype method you linked to for basically one reason: private members. The link you gave supports much better inheritance, but at the cost of not allowing private functions or properties.

    Lacking rich inheretance means I end up keeping my class definitions pretty flat. If i do need to extend a class, I usually end up using more of a Proxy pattern as a substitute for proper inheretance.

    the two class definitions each have their pros and cons, and i think it comes down to personal preference + requirements to decide which way you want to go with this one.

    A cool variant I’ve implemented is, using jQuery, a Controller can manage many Views, as you might see in a tabbed interface where each tab is driven by a separate business object but centrally managed by a Controller in a generic way.

    Very cool! that’s absolutely the way to go. having multiple views feed off data from the same model just makes everything cleaner and more efficient.

    any urls you’d like to show off that feature your variant of the MVC?

    Cheers!

  14. I’m actualy quite interested in how Steven implemented this, and your take on handling multiple views. For example. If you had a wizard that required multiple “screens” of collecting data, and then on the last screen the data was sent to the server, where would the data object before it’s sent off? In the Controller? or in the Model? My first guess would be the object hosting the data being collected would be stored in the model and updated throughout the screen transitions, but I have a feeling it’s not so simple.

  15. (Email notifications of comments is great!)

    @Chris, I think the key abstraction bridging views and data is the form elements themselves.

    Using jQuery this is easy.

    For example, when creating the view you can pass-in any container selector and, in the view::init(), snurf-out all the forms therein.

    Remember it’s the forms that contain the fields (both visible and hidden), and the very handy jQuery Deserialize plugin (http://www.reach1to1.com/sandbox/jquery/testform.html) works on a form-basis.

    So creating a view is a matter of passing-in a comma-delimited list of form selectors, or comma-delimeted list of containers that may (or may not) contain the forms. Even pass-in the body selector if you want to snag all the forms. It just works.

    So the forms are a natural basis for transient data storage prior to submitting.

    Implementation details can vary but, in Adam’s model, the submit action triggers a notification to listeners and, at that point, a specialized listener can iterate through one or more views managed by the controller and, within each view, iterate the forms and marshall the data from each one prior to an ::ajaxSubmit()

    Note too that you could hook-in the most excellent Form Validation plugin and trigger the marshalling after successful client-side validation, which is a bonus.

    I’m at that stage now, and running into the usual Javascript problems of properly referencing objects called from delegated functions called from other delegated functions without resorting to global-scope, or equivalent-to-global-scope kluges.

    At the moment my design has a variable addressed as $.MVC where, regardless of the depth of delegation, I can always find the (so far singleton) controller and its (so far singleton) model.

    I’m not comfy with the notion of the model object as a singleton. What I have now works but I can foresee the day when this simplification will be onerous. The underlying question to resolve is, assuming no spaghetti, which model is immutably tied to which view?

    That’s not a trivial problem, and I sense that I’m one use-case away from having to address it. I might resort to a collection of model-view pairs maintained by the (so far singleton) controller where the views remain a wrapper for one or more forms. That part is working great.

    All that said, I’m pretty happy with subtyping models and controllers so far.

  16. @Stephen

    Thanks for your insight. I can see how forms are good for holding data prior to transmission, but I think my particular case may need a different architecture.

    I’m contemplating rewriting an old order entry system for a local bakery. Previously I wrote it in ASP.NET and it had multiple pages, with no AJAX. There are at least 15 different screens/subscreens allowing for customizing of hundreds of goods, and throughout each page, I accumulated all of the data in a session object (which I regret, b/c session is a pain), and that session object would transcend from page to page. I’d like to rewrite it to use the single-page MVC model. But the catch is, after each item was selected/modified, the total price in the top right would have to update, meaning the order would have to be processed on each user action. To have to comb through the DOM, retrieve each item’s price on every user action seems like too much

    That being said, my first thought would to be make a js object that keeps a running tally of what was selected/modified throughout the order process, much like a bar tab. Every time the user clicks something, the listeners would alert the controller, and the controller would update the variable with the changes. After a few screens the order would look something like this:

    var order = {
    name: ‘Joe Smith’,
    location: ‘Southwest’,
    orderdate: ’07/17/2009′,
    delivery: ‘pickup’,
    payment: {
    type: Visa,
    card: 5555555555555555,
    expMonth: 9,
    expYear: 8
    },
    items: {
    desserts: [
    { name: ‘Chocolate Cake’, quantity: 1, price: 9.99, message: ‘Happy Birthday Jim!!!’ },
    { name: ‘Pudding Cake’, quantity: 2, price: 13.99, message: ‘Another message’ },
    { name: ‘Carrot Cake’, quantity: 4, price: 8.99, message: ‘None’ },
    ],
    drinks: [
    { name: ‘Sweet Tea’, quantity: 1, size: ‘128oz’, price: 2.99 },
    { name: ‘Orange Soda’, quantity: 2, size: ‘128oz’, price: 1.99 },
    { name: ‘Fruit Punch’, quantity: 4, size: ‘128oz’, price: 2.99 },
    ]
    }
    };

    When the user submits the order, then the controller would instruct the model to pass the order as json to the server and the server would then save it.

    Loading an existing order would work in the reverse fashion. A controller would take the existing order, loop through each type of item, pass each portion of the order to the appropriate view, and each view would update its DOM elements accordingly.

    Another option would be to send an AJAX call to the server, and the server temporarily store it either in a session object or a temp db table, and return the updated price, but this would require an AJAX call every time the user clicks an element, which isn’t very practical.

    Anyway, please let me know if I’m on the right track here. Thanks again.

  17. A couple of ideas, bearing in mind that I’m looking at a vast simplification of your structures.

    1) No need to repeatedly comb through the DOM. You could, for example, assign a common class to all the “total” fields on the various pages, cache them as a single jQuery object and, at event junctures, spin through them summing the values then displaying the sum.

    Even if the number of these ‘total’ fields is dynamic, you can always get to them pretty efficiently by addressing their parent containers, which greatly cuts down on the DOM iteration costs.

    So once you’ve combed the DOM once, you cache the references (or parent container references) for quick and speedy subsequent access to particular values.

    2) You may have an opportunity to normaliza and flatten your json structire. Rather than

    items{deserts: [], drinks: []…}

    You could make ‘deserts’ and ‘drinks’ an attribute of each item. This looks doable because, regardless of the structure of item, “quantity” and “price” look consistent and, by my eye, that’s all you need for the dynamic total calculations.

    Point being: if you can normalize the item structure then that makes dynamic access more straightforward, especially if the semantic differences between item types aren’t really relevant to the display dynamics.

  18. Unfortunately I haven’t had any time to devote to this lately. That said, I have some plane flights coming up this month, so I’ll dedicate that time to working on the next phase of the tutorial.

    Apologies for the delay!

  19. hey, i think the jquery mvc idea is great. i wonder y the tutorial has seized?

    jquery is now at 1.4.2… any of you guys know a good jquery mvc tutorial?

    thanks

  20. Like anything else in development, you’ll have to decide if the trade-off of this kind of separation is worth it. For small applications where you only have a few functions, this type of separation is surely overkill. The larger your application gets, though, the more it benefits from the separating code into Model, View, and Controller.
    JavaScriptMVC
    JavaScript MVC conception

  21. For any type of javascript work that’s bigger than an example or a function or two, I’ve used this setup. It’s served me well over the past year or so. The only thing I’m curious about is how to get inheritance to work with this model. I know I can use .extend, but that doesn’t allow overriding methods.

  22. Hey all, thanks for the continued interest in the tutorial! I finally have time back on my hands, and am rounding up projects that I’d never completed.

    Expect to see some new tutorials for this in the coming weeks 🙂

  23. Awesome tutorial!

    Was familiar with Javascript/JQuery but never got down to patterns. I find the Observer pattern pretty interesting for UIs. Has a server side(PHP) developer I never really got to the single page application. Now I only want to do SPA and get more involve with frontend.

    Thanks for taking the time!

    Namasté!

  24. Hi Adam,

    I really like your tutorial, look very easy and right way to manage the spaghetti code.

    How do you think will be the right way to mange a very big website, that have many of views and controllers on the server side.

    Would you create separate view/controller files for each view/controller server files ?

    Thanks,
    Zohar

    1. Only a _few_ months late on the reply here… 🙂

      I think the answer is an unfortunate “it depends.” Sometimes the JS view controllers will be responsible for the same piece of UI that the server’s view controllers are responsible for, but there will be many cases where they’d need to be different. I wouldn’t think about “should I mirror my view controllers?”, I would think about “What should this JS view controller actually control?” and modularize from there.

Leave a Reply

Your email address will not be published. Required fields are marked *