MVC with Javascript

Published on and tagged with cakephp  javascript  jquery  mvc

Javascript was one of those things I tried to avoid up to now. I don’t know why, but somehow I disliked it (probably because it was a pain to use it in the early days of Javascript) ;-) Sure, I used a bit of Ajax here and there, but thanks to the CakePHP Ajax helper I didn’t had to touch the Javascript.

Lately, I decided to do an Ajax application and so I had to learn Javascript. To make my life easier, I decided to use the JQuery framework. I have chosen JQuery over Prototype because I heard many good things about JQuery, and the API documentation was (and still is) more intuitive.

Of course, my first attempt ended in a total mess. The result looked more like spaghetti than code ;-) That’s when I recalled an article (in German) about a Javascript MVC framework called Jamal, developed by Timo Derstappen. From the Jamal website:

The MVC concept is easy to adopt for javascript

  • Controller: Interaction with the user interface (events)
  • Model: Business Logic and AJAX calls
  • View: DOM, CSS modifications

That makes sense. So I had a closer look at Jamal. It looked nice, but it bothered me that you would have to use a CSS class “jamal” in the HTML code to make it work. So I wrote my own implementation called “jscake” which avoids that. You can find the first version in the downloads section.

Let’s create a simple “Hello world” example with jscake. Our example (CakePHP) view will contain a link and a div to show the messages:

<a href="">click</a>
<div id="messages"></div>

First we create our model. All models are in the “$m” namespace (please correct me if that is the wrong term), which is a shortcut for “jscake.models”. So our model is called “$m.Example”. The model contains one function to return the text which should be displayed:

// app/webroot/js/models/example.js
$m.Example = {
	
    getText: function() {
        return "hello world";
    }
};

The view is similar to the model, it contains only one function, too. In the function the element with the id “messages” is located and the text appended to that element. Similar to the models the views are in the “$v” namespace.

// app/webroot/js/views/examples.js
$v.Examples = {
	
    showMessage: function(message) {
        $('#messages').append(message);
    }
};

Last, but not least, we have to create the controller. The index function is automatically called when the JQuery ready event occurs. In this function we simply say that when someone clicks on the link, the other function of the controller (sayHelloWorld) should be executed.

//app/webroot/js/controllers/examples_controller.js
$c.ExamplesController = {

    index: function() {
        $('a').click(this.sayHelloWorld);	
    },
	
    sayHelloWorld: function() {
        $v.Examples.showMessage($m.Example.getText());

        return false;
    }
};

To make our example work we have to include all needed Javascript files in our view, with CakePHP 1.2 it looks like:

<?php $javascript->link(array('jquery-1.1.2', 'jscake', 'controllers/examples_controller', 
'models/example', 'views/examples', 'start'), false); ?>
<a href="">click</a>
<div id="messages"></div>

Have fun with jscake! Feedback is welcome :)

20 comments baked

  • Timo Derstappen

    Hey Daniel,

    nice fork ;)

    The problem I have with your solution is that I like to first not care about the included javascript files and second to have a packed version of my js app. Everything in one file, like jQuery does, with a revision number at the end of the file to prevent browsers from caching an old version.

    I followed the metadata discussion on jquerys dev list and thought that this would be a nice way. Without whitespace the json in the class attribute still validates. Before that I’ve tried to build a routes array like cake does, but this ended up in too much redundancy.

    Your approach would possibly work with every controller/model/view separatly packed, but you still have to include the different javascript files ‘manually’ which isn’t that CoC.

    Btw I’ve put up a new jamal version with some more documentation. I’m happy and open to discuss a good solution for every baker.

    Let’s join forces :)

  • Ahsan

    Very interesting article indeed. Thanks.

  • m3nt0r

    I checked the project out a couple weeks ago. I liked the idea. But then i thought about the bunch of files i would have to create, maintain and include. Its might be still fun to write it this way but it should be merged for production. I am into prototype and developed some sort of mvc my own by creating a generic render and interface class. but thats always in one big file i then pack and gzip. As said.. its a good idea here, but not practical imho.

  • Adeel Khan

    Yeah, I think it would be pretty annoying to have so many javascript files. IMHO, jQuery is good enough on its own. :-)

  • Timo Derstappen

    As I said, I have only one file that is deployed. All files are concatenated and packed with Dean Edwards packer, exactly like jquery does it. So in development it’s easy to debug and on the live server it is small and obfruscated.

    There is an ant task in the jamal archive, which does the packing. Try it out it doesn’t matter if it’s jquery or prototype just care about your js syntax. One mistake and the packed version isn’t working at all :)

  • cakebaker

    @all: Thanks for your comments.

    @Timo: Hm, it wasn’t the goal of my solution to have everything in one file. The idea was to pack every js file separately. Maybe I understood your approach wrong, but to me it seems a bit cumbersome to introduce a deployment process for the js files during the development phase.

    I will have a look at the new version.

    Btw: What means “CoC”?

  • Timo Derstappen

    CoC = Convention over Configuration.

    Think of your javascript as cake application. You will have calls to multiple models in a controller action. There are request actions to other controllers. And to be DRY you need some components (eg jquery plugins/widgets). So if I understand you right you have to configure all the included javascript files for every single page. Why not pack the whole application in one file and let the browser cache it as long as there is a new version.

    Of course during development you keep the different js files unpacked so it is easier to debug. Only if you deploy to stage/live environment your js and css will be packed.

  • cakebaker

    @Time: Sounds logical ;-) So in your development environment you include all js files separately whereas in the staging/live environment you include only a all-in-one js file.

    Yes, my idea was to configure the included js files for every single page (at least those which aren’t used everywhere). But it seems I have to rethink this approach.

  • Glen’s Corner - » Trying some cake

    […] MVC with JavaScript […]

  • Steve

    I started another open source JavaScript MVC awhile ago, called TrimJunction. It was also inspired by Ruby on Rails. http://code.google.com/p/trimpath/wiki/TrimJunction

  • cakebaker

    @Steve: Thanks for the link.

  • Codeville

    If you want a really simple way to do MVC user interfaces with Javascript, you could check out jMVC at http://blog.codeville.net/2007/10/04/rich-javascript-mvc-user-interfaces-with-jmvc/

  • cakebaker

    @Codeville: Thanks for your link.

  • Justin

    If you are looking for client side MVC check out Junction:

    http://jupiterit.com/junction.html

    It’s got templates, built in history support, and automatically loads the controllers and views. It’s really good at connecting to services.

  • cakebaker

    @Justin: Thanks for the link.

  • Open Ideas Sharing » Blog Archive » Javascript MVC
  • Justin Meyer

    Daniel/Timo,
    The old Junction has been replaced by JavaScriptMVC at http://javascriptmvc.com.

    A tremendous amount of work has been done. Here are some of the highlights.

    Include.

    We’ve fixed the problem of having multiple files with an include library that handles including files in the same order cross browser, and compressing them easily. It can compress in the browser, or produce a files list that can be given to a standard compressor. We only have a ruby compressor right now. However, if you are interested, I can get you a php one.

    Model.

    We’ve tightly integrated Eric Mill’s Jester library. It queries Rest interfaces like:
    Todo.find(‘all’ , callback_func );

    Controller.

    The controller has seen some of the greatest improvements. It uses event delegation. So simply writing:

    Controller(‘todos’, {
    click : function() { … }
    })
    Will call click on all DOM elements with class todo. You can also add css selectors to your function names like:
    ‘a.hide mouseover’ : function(){…}
    This would call the function anytime an A tag with className hide is moused over.
    Another great thing is that these events get registered automatically. You never have to reattach event handlers if you change the DOM.

    View.

    We’ve made views really easy with EJS. (EmbeddedJS.com). Rails like helpers, they load from files, caching, etc. They can even get compressed along with all the other files.

    Compatibility.

    We’ve designed JavaScriptMVC to work with other libraries and only include what it needs. For example, if you want to use only the controllers, which require ajax functionality, and you have included prototype, JavaScriptMVC will not load its own ajax functionality, and instead map Prototypes to what it needs.
    Currently, we only have the Prototype masks working, but it’s designed for anything.

    I’d really like to know your thoughts. I feel like this could be a natural fit with CakeBaker and separate it from rails.

  • » MVC JavaScript - just what I need these days….. Knowledge Base: My Knowledge base - everthing I have found that might be useful in .NET, C#, SQL Server 2005, PHP and Actionscript 2.0 / 3.0 etc

    […] MVC JavaScript – just what I need these days….. Posted in March 29th, 2008 by Jimbob in JavaScript http://cakebaker.42dh.com/2007/03/17/mvc-with-javascript/ […]

  • Lindsay

    Hi,

    I made an experimental Hierarchical-MVC framework for Javascript recently:

    http://www.neocoders.com/portal/projects/subo

    cheers,
    Lindsay

  • cakebaker

    @Lindsay: Thanks for the link to your project, I wasn’t aware of it.

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License