How to structure my javascript/jquery code?

JavascriptJquery

Javascript Problem Overview


I am toying around with a pretty intensive ajax based jquery web application. It is getting to a point where I almost loose track of what events that should trigger what actions etc.

I am sort of left with a feeling that my javascript structure is wrong, on a more basic level. How do you guys structure your javascript/jquery code, the event handling etc., any advise for a newbie javascript developer.

Javascript Solutions


Solution 1 - Javascript

AMDS!

It's been awhile since first answers got posted to this question and many things have changed. First and foremost, the JS browser world seems to be moving towards AMDs (asynchronous module definition) for code organization.

The way that works is you write ALL your code as AMD modules, e.g.:

define('moduleName', ['dependency1', 'dependency2'], function (dependency1, dependency2) {
    /*This function will get triggered only after all dependency modules loaded*/
    var module = {/*whatever module object, can be any JS variable here really*/};
    return module;
});

And then modules get loaded using AMD loaders like curl.js or require.js etc, for example:

curl(
    [
        'myApp/moduleA',
        'myApp/moduleB'
    ],
).then(
    function success (A, B) {
        // load myApp here!
    },
    function failure (ex) {
        alert('myApp didn't load. reason: ' + ex.message);
    }
);

Advantages are:

  1. You only have to include single <script> element on your page that loads AMD loader itself (some of them are quite tiny).

  2. After that all JS files will be fetched automatically in asynchronous NON BLOCKING! fashion, thus way faster!

  3. Necessary modules will get executed only after its dependencies got loaded.

  4. Modular (which means code that is easier to maintain and re-use).

  5. Global variables pollution can be completely curbed if used correctly.

Honestly, once concept has clicked in your head, you'll never go back to your old ways.

P.S: jQuery does register itself as AMD module starting from version 1.7.

More information on AMDS:

Solution 2 - Javascript

For javascript code I found the following links from Christian Heilmann indispensable

I also really like the method described by Peter Michaux here

For jQuery, I heartily recommend reading the guides on Authoring and I found this tutorial on jQuery plugin patterns very good

Solution 3 - Javascript

To keep my events in control I use a publish/subscribe mechanism

jQuery.subscribe = function( eventName, obj, method ){
    $(window).bind( eventName, function() {
        obj[method].apply( obj, Array.prototype.slice.call( arguments, 1 ) );
    });
    return jQuery;
}

jQuery.publish = function(eventName){
    $( window ).trigger( eventName, Array.prototype.slice.call( arguments, 1 ) );
    return jQuery;
}

Here's an example of its use

// a couple of objects to work with
var myObj = {
	method1: function( arg ) {
		alert( 'myObj::method1 says: '+arg );
	},
	method2: function( arg1, arg2 ) {
		alert( arg1 );
		//republish
		$.publish( 'anEventNameIMadeUp', arg2 );
	}
}

var myOtherObj = {
	say: function(arg){
		alert('myOtherObj::say says: ' + arg);
	}
}



// you can then have all your event connections in one place

//myObj::method2 is now listening for the 'start' event 
$.subscribe( 'start', myObj, 'method2' );

//myOtherObj::say is now listening for the 'another' event
$.subscribe( 'anotherEvent', myOtherObj, 'say' );

//myObj::method1 is now listening for the 'anEventNameIMadeUp' event
$.subscribe( 'anEventNameIMadeUp', myObj, 'method1' );
//so is myOtherObj::say
$.subscribe( 'anEventNameIMadeUp', myOtherObj, 'say' );


// ok, trigger some events (this could happen anywhere)
$.publish( 'start', 'message1', 'message2' );
$.publish( 'anotherEvent', 'another message' );

Solution 4 - Javascript

I definitely recommend reading up on the object literal pattern in addition to the module pattern; here's a good writeup:

http://ajaxian.com/archives/show-love-to-the-object-literal

Solution 5 - Javascript

(function($, window, slice)
{

	$.subscribe = function(eventName, obj, method)
	{
		$(window).bind(eventName, function()
		{
			obj[method].apply(obj, slice.call(arguments, 1));
		});
		return $;
	};

	$.publish = function(eventName)
	{
		$(window).trigger(eventName, slice.call(arguments, 1));
		return jQuery;
	};

})(jQuery, window, Array.prototype.slice);

Solution 6 - Javascript

To add to the existing answers, here's a great post that covers more advanced techniques that build on the Module Pattern.

Once your Javascript code reaches a certain size, you'll inevitably want to refactor it by breaking it into multiple files / modules / sub-modules. If you're not sure how to accomplish this using the module pattern, this article is a must-read.

Solution 7 - Javascript

My js files usually follow a naming convention similar to this :

  • xxx.utility.js
  • mypage.events.js
  • xxx.common.js
  • /lib/
  • /OS-DoNotDistribute/lib/

Where

  • 'mypage' is the name of the html, aspx, php, etc file.
  • 'xxx' is the concept. (i.e. orders.common.js)
  • 'utility' signifies it's a reusable library script (i.e. ajax.utility.js, controlfader.utility.js)
  • 'common' is reusable functionality for this app, but not reusable across other projects
  • 'lib' is a subdirectory for any external or library scripts
  • 'OS-DoNotDistribute' is a subdirectory to ensure no OS licensed code is distributed if the app is ever sold.

Also, for ajax, I have a special naming convention for call back functions, so it's easy to tell what they are.

I'm not sure it that's close to what you were looking for, but I hope it helps.

Solution 8 - Javascript

I really like these articles:

http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html

http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/

They helped me to understand how telerik creates extensions for asp.net mvc.

Solution 9 - Javascript

I like the idea of AMDs (see nix's answer).

But I typically compile all my JS files into one JS file. In that case the asynchronous part is not needed. So I wrote a little "Infile Module Loader".

Here it is: https://codereview.stackexchange.com/questions/14530/a-little-infile-amd

Solution 10 - Javascript

We can use mvc pattern in our javascript-jquery applications. (Backbone.js, knockout.js vs.... ) are mature libraries we can use for this aim.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEgil HansenView Question on Stackoverflow
Solution 1 - JavascriptThatGuyView Answer on Stackoverflow
Solution 2 - JavascriptSteerpikeView Answer on Stackoverflow
Solution 3 - JavascriptmeouwView Answer on Stackoverflow
Solution 4 - JavascriptrmurpheyView Answer on Stackoverflow
Solution 5 - JavascriptAkzhanView Answer on Stackoverflow
Solution 6 - JavascriptmbreiningView Answer on Stackoverflow
Solution 7 - JavascriptJohn MacIntyreView Answer on Stackoverflow
Solution 8 - Javascriptdenis_nView Answer on Stackoverflow
Solution 9 - JavascriptbrilloutView Answer on Stackoverflow
Solution 10 - JavascriptiknowitwasyoufredoView Answer on Stackoverflow