Reputation: 8846
Currently I am using a single .js
file for a whole project (plus included libraries). Only occasionally I split the file into multiple files (i.e. front vs back end sections). In the file(s) I attach events (and other functionality) inside of a single jQuery ready
event handler using jQuery selectors:
$(document).ready(function() {
$('#an_element_on_homepage').click(function() {
// do something
});
// ...
// A lot of similar code here
// ...
$('.elements_on_homepage_and_contact_page').click(function() {
// do something
});
});
This is perfectly fine and working, but on a larger project there could be a lot of code executing unnecessarily as some events are needed only at specific pages or there could be id/class collisions between different pages. What is the best practice to avoid the problems and still preserve easy maintainability of the JavaScript and HTML code?
I can think of 2 solutions:
Split .js file into multiple files and on every page choose only the files needed. However, it could be hard to distribute the event attachments properly and could cause problems in caching the scripts on client side.
Wrap the event attachments in functions and call them from a HTML code only where needed. Something like:
function attachClickOnElementOnHomepage() {
$('#an_element_on_homepage').click(function() {
// do something
});
}
And after in HTML:
<div id="an_element_on_homepage"></div>
<script type="text/javascript">attachClickOnElementOnHomepage();<script>
However, I have a feeling this is also not the best solution possible.
Can you think of another/better solutions?
Upvotes: 1
Views: 308
Reputation: 39980
Solution 1. is, as you say, not particularly efficient with regards to HTTP roundtrips, although you can probably choose to ignore that concern if you're making an internal application.
Solution 2. just looks like a roundabout way of inline event handler registrations.
The pattern I use is one JS file that has any code I want to reuse as a project-specific "library" – there's rarely enough of it to warrant splitting it up. And one JS file per unit of server-side code – MVC controller, stand-alone Wicket control – that implements only page-specific behaviour, or wires up to the reusable code. This file is usually named after the controller.
The advantages:
A possible downside is that some code may be repeated between the page-specific scripts, but that's the cost of separating mechanism from policy. This mostly happens to me for trivial code like setting up jQuery UI buttons or Chosen selectboxes; since they share a common theme, my solution was to roll these up into a single JS file for "ui enhancements".
You could also look into tooling that will combine fine-grained maintainable javascripts into easier to load ones as a build step; for a large project where the performance gains matter, the effort in maintaining this might not be overkill. The specifics would depend on what your other tooling is, a fallback solution could be as simple as a shellscript that calls the command-line version of jsmin.
Upvotes: 1
Reputation: 95
This is a classical issue of code structure.
Separate your views into widgets (think plugins). If you have models in your app, separate their declaration from the main onReady event, fire events in your model and allow UI widgets to interact with your models.
Mostly, separate your files in order to: * have a clearer view of your work * separate concerns, and expose only what is required
For instance, consider that nothing exists appart from what is located in your file. If you do any use of variables that are not declared in-file, consider you've broken the principle of separation of concerns.
As an example:
var myModel = function () {/**...**/};
var myModel.prototype.save = function () {/**...**/}
var myUIElt = function (model) {
this.render(); //Do whatever required
this.bind('onchange', function() { model.update();});
};
With, such, in your onReady callback, you'll have:
$(function() { var elt = new myUIElt(); }); // Much cleaner, huh ? ;)
In the real world, things may be a little more complicated, but the main idea is the one above.
Don't hesitate to ask for more details,
HTH,
Upvotes: 2
Reputation: 1136
you can organize your code in modules with init function defined inside each module
and then call the moduleName.init() function only if needed element is present on currently loaded page
something like
var homePageModule = {
init: function() {
$('#an_element_on_homepage').click(function() {
});
anotherFunction();
},
anotherFunction: function() {
//do something
}
};
//check for elements
$(function() {
if ($('#an_element_on_homepage').length) {
homePageModule.init();
}
});
P.S.: or use classes and instantiate them accordingly to element presence
Upvotes: 0