Blogger.create { :name =>'Matt Aimonetti',
:location => 'San Diego, Ca',
:email => mattaimonetti AT gmail.com,
:linkedin => Matt's Linkedin page,
:recommend_me => HERE,
:contractor => true}

keeping my javascript files organized

Written by matt on December 4th, 2007

I was recently asked by Rubyist friend (Josh Knowles) how I was organizing my Javascript files when using LowPro.

LowPro is the best solution for doing Unobtrusive Javascript using Prototype.

With the help of LowPro, you define behaviors that get triggered by the user. This is great, however, you'll notice that some behaviors are used all over the place (a date chooser for instance) and some complicated behaviors only get used on very specific pages.

First things first, let's look at the header in my application.html.erb file (located in app/views/layouts). This is the default layout used by all my views, I rarely use more than 5 layouts per app and always use a default layout.

Please note that I'm using Rails 2.0 so some features you'll see in my file won't work in Rails 1.2.x. (if you want to know about all the new Rails sexiness, check on this awesome Peepcode PDF.

Here we go:

1
2
3
  <%= javascript_include_tag 'prototype', 'effects', :cache => true %>
  <%= javascript_include_tag 'lowpro', :cache => true %>
  <%= javascript_include_tag  'application', :cache => true %>

The first thing you might notice is that I don't use


  <%= javascript_include_tag :defaults %>

The reason? I don't want to load prototype.js, effects.js, controls.js, dragdrop.js, and application.js all at once. I almost never use drag'n'drop and seldom use Autocompleter and InPlaceEditor so why loading them in each and every single page of my apps? I'm not saying they are bad libraries, I'm just saying that in more than 80% of my page, I don't use them, so they should not be in my default page load.

The second thing you might notice, I use :cache => true. Asset caching is a new feature in Rails 2.0 which combines related assets into a single file (works with css and js and only in production mode) Note that the above code is untested, but everything should be loaded properly, otherwise, make sure proto gets loaded first, then lowpro, then application. (and you can probably create a one-liner)

All the default behaviors are defined in the application.js file, so they get loaded on all page. However to handle action specific behaviors, I use another Rails trick right in the header:


 <%= yield :javascript %>

Why? Very simple, I want to load some custom JS in the header depending on the action that is used. For instance, when a visitor goes to my fancy ajax photo editor, I want to load the content editor javascript right in the header where it belongs.

For that, I simply need to add the following to my view:

1
2
3
  <% content_for :javascript do %>
    <%= javascript_include_tag "photos_show" %>
  <% end %>

If content_for :javascript isn't define, noting is yield in my header and therefore nothing is included but whenever I need, I can access my header directly from the view and insert javascript code in a very clean way.

photos_show.js is the javascript defining all the behaviors related to the photos controller and the show action. I usually only have few actions with a lot of custom behaviors so, these structure works well for me.

1
2
3
4
5
  javascripts
    \controller_action.js
    \controller_another_action.js
    \another_controller_action.js
    ...

However in the case of an app with a lot of custom behaviors, I recommend using the following structure:

1
2
3
4
5
6
  javascripts
    \ controller_name_
            \action_name_.js
      \another_controller_name
              \action_name_.js
  ...

That's it folks, I'm not a javascript expert, and if you know better, don't hesitate to leave me a comment. What I know for sure, is that since I started using LowPro and behavior driven with Prototype, I have much more fun. Adding a bit of structure is a simple way for me to keep my code clear and help other people who have to work with me. (more on that later)



Comments

  • Josh Knowles on 04 Dec 21:54

    Thanks for the tips Matt!

  • Robert on 05 Dec 22:07

    Great suggestions and very timely for a personal project using google maps - content_for will be especially helpful.

  • Jesper Vingborg on 06 Dec 01:04

    Nice piece. I might add that this technique applies equally well to stylesheets.

  • Fred on 06 Dec 20:23

    Very useful! I had some problems structuring my code- everything seemed to end up in public/javascripts, now it back in the right place with the views. Thanks!!

  • Matt Aimonetti on 07 Dec 00:30

    Our very Patrick Crowley aka Mokolabs wrote a plugin to handle javascript files: http://the.railsi.st/2007/8/22/javascripter-organize-your-javascript

    Check it out!

Comments are closed