debuggable

 
Contact Us
 

How to organize your CakePHP App's Javascript?

Posted on 10/10/06 by Felix Geisendörfer

Deprecated post

The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.

Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.

Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).

Ok, I'm no expert on Javascript but I know enough to have some fun with it. Unlike lot's of folks, I'm not into using all those bloated JS libs, frameworks and other things around. However, I'm in love with the lightweight jQuery library, since it allows to write amazingly elegant code that's easy for others to read, and fun to work with. One of the coolest aspects about jQuery is that it doesn't use prototypes to turn Javascript into a new language (like the Prototype library does), but rather encapsulates all functionality into the $ object that is used as a wrapper/selector for the elements you want to manipulate. So if your app includes more then 100 kbyte of JS bloat right now, do yourself a favor and switch to the fresh jQuery 1.0.2. It will not only reduce your JS dependencies to 15kb, but also give you the chance to reduce your own code considerably (2-3x for me).

I didn't mean to go off topic, but when talking about JS I just *have* to mention jQuery these days ; ). To me it's the frontend counterpart for RoR/CakePHP in terms of allowing Rapid Application Development. I also highly recommend it for prototyping web applications (I used it a little bit for my previous redesign attempt).

But what I actually want to start a discussion about, is how one should go about organizing his custom JS code, especially when working with CakePHP. In my early JS days I used to have one or more JS files with a plain list of functions. Most of the time I ended up with ugly spagetti code, so I decided to change my approach. Right now I use the JS version of a globally available Singleton that always has a sub-object called Behaviors that contains a variable amount of functions to be executed when the DOM is ready. The main advantage of this approach is that you can organize your applications functionality in hierarchies, while not having to worry about scoping issues.

But talk is cheap, so let's take a look at a simple example taking out of my Caketaster project that is supposed to enhance the User interface.

var Caketaster = new function()
{
    this.initialize = function()
    {
        Caketaster.Behaviors();
    }
   
    /**
     * All custom behaviors we want to add to our elements are handled in this
     * part of the Caketaster Site Controller
     **/

    this.Behaviors = function()
    {
        for (var fct in Caketaster.Behaviors)
        {
            if (typeof(Caketaster.Behaviors[fct])=='function' && !(Function[fct]))
            {
                Caketaster.Behaviors[fct]();
            }
        }
    }
   
    this.Behaviors.collapseAllTestCases = function()
    {
        $('ul ul').hide();
    }
   
    this.Behaviors.toggleTriggers = function()
    {
        $('h2').click(function(){$('ul', this.parentNode).toggle();});
    }
   
    this.Behaviors.addJsControls = function()
    {
        $('form').after('<div id="js-control"><a href="#">Expand All</a> <a href="#">Expand All Failed</a> <a href="#">Expand All Passed</a></div>');
        $('a', '#js-control').click(Caketaster.Tests.jsControl);
    }
   
    this.Tests = function(){};
    this.Tests.jsControl = function(e)
    {
        e.preventDefault();
       
        var commands = this.innerHTML.split(' ');
       
        if (!commands[2])
            var selector = 'ul ul';
        else
            var selector = 'ul .test-'+commands[2].toLowerCase()+' ul';

        if (commands.shift()=='Expand')
        {
            $(selector).show();
            this.innerHTML = 'Collapse '+commands.join(' ');
        }
        else
        {
            $(selector).hide();
            this.innerHTML = 'Expand '+commands.join(' ');
        }
       
        return false;
    }
}

$(document).ready(Caketaster.initialize);

This code essentially only adds some JS controls to the test suites user interface allowing to expand & collapse the test cases that were executed.

The name of the Singleton is always the name of the project I use it in. But I guess it would be better to name it SiteController or something like this since I always have to replace all occurences of the Project name when reusing it right now. But besides that, the concept has worked very nicely for me so far, keeping in mind that I'm not surfing the web 2.0 wave too hard, having only small JS needs.

But I know a lot of you folks are writing as much JS as PHP for their applications, so my question is, how do you organize your CakePHP's applications JS? Is somebody using a more advanced M(html), C(js), V(css) pattern for his front end? I think making some CakePHP variables like webroot, here and base is a cool thing to do, but I guess there is more. I'm not asking for a super complex framework, but just some best practices / conventions you guys are using to streamline your JS workflow and maybe some comments on my current approach.

--Felix Geisendörfer aka the_undefined

 
&nsbp;

You can skip to the end and add a comment.

Leandro Ardissone said on Oct 10, 2006:

Nice article.
Also I love that you use my overloved jQuery library, so it's very useful for me that I'm beginning with CakePHP.

Thanks

Felix Geisendörfer said on Oct 10, 2006:

Uhm, this was more ment to be the start for a discussion rather then a real article ; ). I think there are people who know a lot more about JS then I do (which is easy), and hope for them to share some advice with me and other part-time JS coders .

Reen said on Oct 10, 2006:

I'm using the Yahoo User Interface Library (YUI). Most of my code is organized like this:

YAHOO.namespace('avh');

YAHOO.avh.projectName = function() {
var privateVar = null;

return {

init: function() {

//public Function

},

other: function() {

}

};

}();

YAHOO.util.Event.on(window, 'load', YAHOO.avh.projectName.init, YAHOO.avh.projectName,true); //last 2 parameters for scope correction.

I know that yui is a little bit more bloated than jQuery, but it also does no overriding of native JS objects.

Felix Geisendörfer said on Oct 10, 2006:

Reen: Well I like some of the stuff the YAHOO lib does, but to me it feels a lot more like Java then Javascript and that I do not like ; ).

Also, the $(document).ready() function is superrior to window.onLoad because it will fire as soon as the DOM has loaded and not wait for images, and other files to download.

Leandro Ardissone said on Oct 10, 2006:

Totally agree with you Felix..
The Yahoo UI looks powerful, but is pretty dirty to work with it, like Java. IMO.

sole said on Oct 11, 2006:

I suppose your approach is fine if you just have one document which will include that javascript. But what do you do if different sections of the site have different javascript needs?

I don't think it's a good idea to try to apply a long list of behaviours to something that maybe will just match 10% of the rules - mainly for performance reasons :-)

I presume it would be better in that case to split the specific javascript code in several pages and maybe let each controller take care of its needed javascript.

I'm trying to find out how to do that for a project here, if I get to some nice method I'll let you know.

PHPDeveloper.org said on Oct 11, 2006:

Felix Geisendorfer's Blog: How to oragnize your CakePHP App's Javascript?...

...

TommyO said on Oct 23, 2006:

Your statement about building a simple MVC framework really got me thinking. It's a tremendous idea. It also answer's sole's issues about scaling the javascript. Similiar to CakePHP, it could load only those Models an Controllers needed, and apply them to the View defined.

One variation on the MVC as you set it out.
M = JSON - the raw data stored, pulled or generated on the fly

C = Javascript - populating the DOM, creating events

V = DHtml/CSS - simply the definition of the DOM and presentation style

[...] This is a follow up to one of my previous posts called How to organize your CakePHP App’s Javascript. While the old solution was nice to manage the JS of a smaller application, this one is ment to structure your JS even in bigger projects. To make this possible I decided to go with a loose (MV)C pattern. The idea is this: Your global Javascript functions will all go in a JS class called SiteController. This object also has a function called registerController. By calling this function you register that new Controller's behaviors to be called up after the DOM has loaded. [...]

Francis said on Dec 01, 2006:

Google have already done this with their Google Web Toolkit, and it works with eclipse. I am learning it right now on my spare time for past 3 months and looks great when developing an AJAX application.

I guess you wouldn't like it because you will have to code using java :)

Jiri said on Apr 12, 2007:

I usually arrange JS and CSS into controller- and action-specific files. IMO it works well with the way CakePHP projects are structured...

I wrote a small helper to include the files for me automatically, and I guess it might be useful for other people looking for ways to structure their JS and CSS files. You can check it out at http://jirikupiainen.com/2007/04/11/automatically-loading-js-and-css-files-with-cakephp/ .

This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.