views:

89

answers:

6

I've searched a little bit around SO and haven't found any questions/answers that are helping me. The problem is my jQuery function calls are getting much too large to maintain. I'm wondering if I should be refactoring a lot more or if there is a better way to do all of these calls. You'll see as I make one call, the anonymous functions that are arguments for the function end up being very large and make the readability of the code terrible. I could in theory break all these up into their own functions but I don't know if that's a best practice or not. Here is an example of some of the jQuery so far:

$('#dialog').html('A TON OF HTML TO BUILD A FORM').dialog('option', 'buttons', { 'Save': function(){$.post('/use/add/', $('#use_form').serialize(), function(data){ ......There were 4 more lines of this but I'm saving you so you don't rip your eyeballs out hopefully you get the idea.....dialog('option','title','New Use').dialog('open');

As you can see since so many of the functions I'm calling take functions as arguments, when I create anonymous functions I end up with a huge mess (there were about 3 more anonymous function declarations in this code)

Should I simply make a bunch of functions and call those to make it more readable. The only reason I'd be against this is because I'd have a bunch of functions declared that are only used once.

Thanks in advance for the help!

+4  A: 

Define the functions in the correct scope and it's not a big deal.

var generateHTML = function() {
  ...
};
var somethingElse = function() {
  ...
};

... some more ...

$('#dialog').html( generateHTML() )...etc

There's not much else you can do except reorganize your code in general (say, using an object oriented style) to encapsulate code so it isn't so messy.

thenduks
I'm going to choose this as the accepted answer because it seems to be what most people prefer. It was referenced by some other answers as well. I wish I could accept all answers because all of them are insightful and valuable. Thanks for all the great input.
Jordan Messina
+1  A: 

Formatting, formatting, formatting! With proper use of whitespace your code CAN look readable:

$('#dialog').
    html('A TON OF HTML TO BUILD A FORM').
    dialog('option',
        'buttons', {
            'Save': function(){
                var callback = function(data){
                    // There were 4 more lines of this
                    // but I'm saving you so you don't
                    // rip your eyeballs out hopefully
                    // you get the idea
                }
                $.post(
                    '/use/add/',
                    $('#use_form').serialize(),
                    callback
                )
             }
         }).
    dialog('option',
        'title',
        'New Use').
    dialog('open');

This is just how I would personally format it. There are other ways but I'd strongly suggest leaving opening braces/brackets and coutinuing commas/dots/+ at the end of the line because javascript has a tendency to automatically add a ';' at the end of a line if it thinks the line is a complete well-formed statement.

The important thing is not what specific formatting rule you adopt. The important thing is to be consistent about it. In some ways Python was right: it's sometimes good to force people to indent their code (but I hate being forced by Python).

slebetman
+1  A: 

An obvious way to maintain maintainability is to use some sort of formatting.

I understand your dislike of naming singly used functions, but it's easy to contain the names. The javascript idiom to imitate a scope is to wrap the code in question in an anonymous function that's called immediately:

(function () {
  var f = function (x) ...
  var g = function (y, z) ...
  // operations involving f and g
}()); // called immediately

I prefer another form, which makes the fact that the code is executed right away more visible:

new function () { // called immediately
  var f = function (x) ...
  var g = function (y, z) ...
  // operations involving f and g
};

there's another way to create names with this:

new function (i, j, k) {
  // functions f and g
  f(i, g(j, k));
}(3, 4, 5);
just somebody
the self-invoking anonymous function needs to be wrapped in parentheses i.e. `(function() { ... })();`
Russ Cam
thx, I corrected the answer. off to ecma-262 to dig out the rationale.
just somebody
+1  A: 

The only reason I'd be against this is because I'd have a bunch of functions declared that are only used once.

Using anonymous functions as you are currently doing is really no different to declaring correctly scoped named functions, except that they are inline and make it slightly more difficult to debug in many JavaScript debuggers as the function name is not displayed.

If there are any patterns to your anonymous functions across pages, I would attempt to refactor named functions out that provide a common base to the functionality needed.

I'd be inclined to avoid having large strings of html within jQuery method calls or embedded inside JavaScript <script> tags and keep these in a separate location that can be easily queried to retrieve the relevant content - this could be text files, etc.

Russ Cam
A: 

I'd try to decompose the code into plugins as much as possible and in fact design the code around this principle. Not sure how well that idea fits your needs.

reinierpost
Do you mind giving an example and the advantages of doing this over decomposing into different functions?
Jordan Messina
They are different functions, just functions of a particular kind.This is for GUI widgets or modifications. The jQuery code base uses this principle.For instance I once needed a color picker. Found several color pickers in which the color picker functionality was more or less dependent on the HTML already present on the page. Many bits of JavaScript, CCS, and HTML in various places, interacting in subtle ways. Adapting that color picker for my own page took a lot of effort. A color picker should be a plugin that applies anywhere and creates its own DOM elements and CSS specifics.
reinierpost
A: 

It's easy to get into the never ending chaining problem in jQuery. Function chaining is good if used moderately, or it takes forever to read and understand code that was written like 5 minutes ago. In that sense, formatting your code as slebetman suggested would be helpful. In addition scoping your functions as suggested by just somebody or thenduks will also be of great help.

If you were to walk an extra mile in your refactoring efforts, I would suggest you consider some sort of architectural patterns such as MVC or MVP to organize your code. A List Apart has a nice article on implementing MVC with Javascript. If there is a separation of view and models, it easily gives way to using custom events and plenty of other additions that are easily reusable. It also forces thinking in terms of the domain model rather than DOM objects (tables, rows, divs) or events (click, keyup), etc. Thinking in terms of the domain model and associated events such as onPostRollback, onPostCreate or onCommentAdded that might be applicable on SO for instance. jQuery recently added support for binding custom events and these are some good articles (first, second) explaining how tos.

In general, its difficult to reuse views, but models change very little across projects and is one area where we can achieve maximum reusability.

Anurag