Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
67
rated 0 times [  69] [ 2]  / answers: 1 / hits: 47517  / 11 Years ago, fri, may 24, 2013, 12:00:00

The Problem


This answer has been answered before but are old and not up to date. I have over 2000 lines of code in a single file, and as we all know this is bad practice, especially when i'm looking through code or adding new features. I want to better organize my code, for now and for the future.


I should mention that I'm building a tool (not a simple website) with lots of buttons, UI elements, drag, drops, action listeners/handlers and function in the global scope where several listeners may use the same function.


Example code


$('#button1').on('click', function(e){
// Determined action.
update_html();
});

... // Around 75 more of this

function update_html(){ .... }

...

More example code


Conclusion


I really need to organize this code for best use and not to repeat myself and be able to add new features and update old ones. I will be working on this by myself. Some selectors can be 100 lines of code others are 1. I have looked a bit at require.js and found it kinda repetitive, and actually writing more code than needed . I'm open to any possible solution that fit this criteria and link to resource / examples are always a plus.


Thanks.


More From » jquery

 Answers
3

I'll go over some simple things that may, or may not, help you. Some might be obvious, some might be extremely arcane.



Step 1: Compartmentalize your code



Separating your code into multiple, modular units is a very good first step. Round up what works together and put them in their own little encased unit. don't worry about the format for now, keep it inline. The structure is a later point.



So, suppose you have a page like this:



enter



It would make sense to compartmentalize so that all the header-related event handlers/binders are in there, for ease of maintenance (and not having to sift through 1000 lines).



You can then use a tool such as Grunt to re-build your JS back to a single unit.



Step 1a: Dependency management



Use a library such as RequireJS or CommonJS to implement something called AMD. Asynchronous Module Loading allows you to explicitely state what your code depends on, which then allows you to offload the library-calling to the code. You can just literally say This needs jQuery and the AMD will load it, and execute your code when jQuery is available.



This also has a hidden gem: the library loading will be done the second the DOM is ready, not before. This no longer halts load-up of your page!



Step 2: Modularize



See the wireframe? I have two ad units. They'll most likely have shared event listeners.



Your task in this step is to identify the points of repetition in your code and to try to synthesise all this into modules. Modules, right now, will encompass everything. We'll split stuff as we go along.



The whole idea of this step is to go from step 1 and delete all the copy-pastas, to replace them with units that are loosely coupled. So, instead of having:



ad_unit1.js



 $(#au1).click(function() { ... });


ad_unit2.js



 $(#au2).click(function() { ... });


I will have:



ad_unit.js:



 var AdUnit = function(elem) {
this.element = elem || new jQuery();
}
AdUnit.prototype.bindEvents = function() {
... Events go here
}


page.js:



 var AUs = new AdUnit($(#au1,#au2));
AUs.bindEvents();


Which allows you to compartmentalize between your events and your markup in addition to getting rid of repetition. This is a pretty decent step and we'll extend this further later on.



Step 3: Pick a framework!



If you'd like to modularize and reduce repetitions even further, there are a bunch of awesome frameworks around that implement MVC (Model - View - Controller) approaches. My favourite is Backbone/Spine, however, there's also Angular, Yii, ... The list goes on.



A Model represents your data.



A View represents your mark-up and all the events associated to it



A Controller represents your business logic - in other words, the controller tells the page what views to load and what models to use.



This will be a significant learning step, but the prize is worth it: it favours clean, modular code over spaghetti.



There are plenty of other things you can do, those are just guidelines and ideas.



Code-specific changes



Here are some specific improvements to your code:



 $('.new_layer').click(function(){

dialog(Create new layer,Enter your layer name,_input, {

'OK' : function(){

var reply = $('.dialog_input').val();

if( reply != null && reply != ){

var name = ln_+reply.split(' ').join('_');
var parent = ;

if(selected_folder != ){
parent = selected_folder+ .content;
}

$R.find(.layer).clone()
.addClass(name).html(reply)
.appendTo(#layer_groups +parent);

$R.find(.layers_group).clone()
.addClass(name).appendTo('#canvas '+selected_folder);

}

}

});
});


This is better written as:



$(body).on(click,.new_layer, function() {
dialog(Create new layer, Enter your layer name, _input, {
OK: function() {
// There must be a way to get the input from here using this, if it is a standard library. If you wrote your own, make the value retrievable using something other than a class selector (horrible performance + scoping +multiple instance issues)

// This is where the view comes into play. Instead of cloning, bind the rendering into a JS prototype, and instantiate it. It means that you only have to modify stuff in one place, you don't risk cloning events with it, and you can test your Layer stand-alone
var newLayer = new Layer();
newLayer
.setName(name)
.bindToGroup(parent);
}
});
});


Earlier in your code:



window.Layer = function() {
this.instance = $(<div>);
// Markup generated here
};
window.Layer.prototype = {
setName: function(newName) {
},
bindToGroup: function(parentNode) {
}
}


Suddenly, you have a way to create a standard layer from anywhere in your code without copy pasting. You're doing this in five different places. I've just saved you five copy-pastes.



One more:



// Ruleset wrapper for actions



var PageElements = function(ruleSet) {
ruleSet = ruleSet || [];
this.rules = [];
for (var i = 0; i < ruleSet.length; i++) {
if (ruleSet[i].target && ruleSet[i].action) {
this.rules.push(ruleSet[i]);
}
}
}
PageElements.prototype.run = function(elem) {
for (var i = 0; i < this.rules.length; i++) {
this.rules[i].action.apply(elem.find(this.rules.target));
}
}

var GlobalRules = new PageElements([
{
target: .draggable,
action: function() { this.draggable({
cancel: div#scrolling, .content,
containment: document
});
}
},
{
target :.resizable,
action: function() {
this.resizable({
handles: all,
zIndex: 0,
containment: document
});
}
}

]);

GlobalRules.run($(body));

// If you need to add elements later on, you can just call GlobalRules.run(yourNewElement);


This is a very potent way to register rules if you have events that are not standard, or creation events. This is also seriously kick-ass when combined with a pub/sub notification system and when bound to an event you fire whenever you create elements. Fire'n'forget modular event binding!


[#78042] Thursday, May 23, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
irvingcarloe

Total Points: 677
Total Questions: 109
Total Answers: 96

Location: Svalbard and Jan Mayen
Member since Sun, Sep 25, 2022
2 Years ago
irvingcarloe questions
Wed, Mar 31, 21, 00:00, 3 Years ago
Tue, Aug 4, 20, 00:00, 4 Years ago
Fri, Jul 3, 20, 00:00, 4 Years ago
;