9

When building webapps with MVC web framworks like Django, Kohana, Rails and the like, I put together the application without JS-driven components initially, and then add them afterwards as "improvements" to the UI.

This approach leads to non-intrusive JS, but I don't have a good "standard" way of how to go about organizing the JS work. Most of the JS I write in apps like these are 10-30 line JQuery snippets that hook into some very specific part of the UI.

So far I often end up inlining these things together with the part of the UI they manage. This makes me feel dirty, I'd like to keep the JS code as organized as the python / php / ruby code, I'd like for it to be testable and I'd like for it to be reusable.

What is the best way to go about organizing JS code in a setup like this, where we're not building a full-blown JS client app, and the main meat is still server side?

axtavt
  • 239,438
  • 41
  • 511
  • 482
jakewins
  • 963
  • 1
  • 6
  • 6

4 Answers4

1

I am also very interested in what other people have to say about this. The approach I've taken is to use object literal notation to store the bulk of the function, and store these in one file included on all pages (the library)

uiHelper = {
    inputDefault:function(defaulttext){
    // function to swap default text into input elements
    },
    loadSubSection:function(url){
    // loads new page using ajax instead of refreshing page
    },
    makeSortable:function(){
    // apply jQuery UI sortable properties to list and remove non javascript controls
    }
}

Then I include a .js file on any page that needs to use the library that ties the elements on that page to the function in the library. I've tried to make each function as reuseable as possible and sometimes the event binding function on the page calls several of my library functions.

$(document).ready(function(){
    $('#mybutton').live('click',uiHelper.loadSubSection);

    //more complicated helper
    $('#myotherbutton').live('click',function(){
        uiHelper.doThisThing;
        uiHelper.andThisThing;
    });
});

edit: using jsDoc http://jsdoc.sourceforge.net/ notation for commenting for these functions can produce documentation for the 'library' and helps keep your code easy to read (functions split by comments).

The following question is along similar lines to your own - you should check it out...

Commonly accepted best practices around code organization in JavaScript

Community
  • 1
  • 1
calumbrodie
  • 4,722
  • 5
  • 35
  • 63
  • I think this is in the correct direction, putting together a library of generalized UI methods. That opens up, like you say, for having a proper file structure, which in turn allows automatic builds w/ documentation, testing, minification and so on. It still requires inlining stuff with the template. Perhaps simply having a js file directly included in the template (something like mytemplate.html and mytemplate.html.js) that does the event binding.. – jakewins Nov 03 '10 at 14:11
  • In my current application my controller is aware of its url (for example 'users/edit/') and checks to see if a partner .js file exists on the file system. If so, it passes this information to the template, which includes it automatically using the url as the convention to load the js file. In this case it would know to load /js/pages/users/edit.js. I minify/concatenate and cache at runtime using http://code.google.com/p/minify/ – calumbrodie Nov 03 '10 at 21:01
  • I was looking into doing something similar for my Django apps. I'd like for an automated system to connect js files with templates. It seems that low-level support for accessing the actual template name from within the template is missing, so this becomes difficult. I wrote a small template tag to add in the bottom of templates to manually include js and wrap it in appropriate boilerplate.. – jakewins Nov 04 '10 at 11:03
0

When dealing with JS code, you should first analyze whether it will be used right away when the page loads. If it's not used right away (meaning the user must do something to invoke it) you should package this into a JS file and include it later so the load time is perceived faster for the user. This means that anything that the user will sees should go first and JS related to the functionality should be imported near the end of the file. Download this tool to analyze your website: http://getfirebug.com/ If the JS code is small enough, it should just be inline with the HTML. Hope that helps a bit.

bhavinp
  • 823
  • 1
  • 9
  • 18
0

For quick little user interface things like that I put everything into a single javascript file that I include on every page. Then in the javascript file I check what exists on the page and run code accordingly. I might have this in UIMagic.js for example. I have jQuery, so excuse those jQuery-isms if they aren't familiar to you.

function setupMenuHover() {
  if ($("li.menu").length) { // The page has a menu
    $("li.menu").hover(function() { ... }, function() { ... });
  }
}
$(setupMenuHover);

function setupFacebookWizbang() {
  if (typeof FB != "undefined") { // The page has Facebook's Javascript API
    ...
  }
}
$(setupFacebookWizbang);

I've found this to be a sane enough approach.

Dave Aaron Smith
  • 4,517
  • 32
  • 37
0

My preferred method is to store inline javascript in it's own file (so that I can edit it easily with syntax highlighting etc.), and then include it on the page by loading the contents directly:

'<script type="text/javascript">'+open('~/js/page-inline.js').read()+'</script>'

This may not perform well though, unless your templating library can cache this sort of thing.

With Django you might be able to just include the js file:

<script type="text/javascript">
    {% include "js/page-inline.js" %}
</script>

Not sure if that caches the output.

If you are still worried about being 'dirty', then you could check out the following projects, which try to bridge the server/client side language mismatch:

http://pyjs.org/ (Python generating JavaScript)

http://code.google.com/webtoolkit/ (Java generating JavaScript)

http://nodejs.org/ (JavaScript all the way!)

EoghanM
  • 25,161
  • 23
  • 90
  • 123