I am using jquery and am really frustrated at how I write my code. I started coding in JS and Jquery a few months ago and my code looked like this:
$(document).ready(function(){
$(function(){// a function that applies a plugin to an element});
$(function(){// another function that applies a plugin to an element});
$(function(){// and another function that applies a plugin to an element});
$(function(){// yet another function that applies a plugin to an element});
});
$(function(){//functions applied to certain elements that does not require to be initially loaded})
basically what I did before was put everything inside the $(document).ready
and here's how I am coding now
function a(){//a function that applies plugin to an element}
function b() {// another function}
$(document.ready(function(){a(); b();});
$(function(){//functions applied to certain elements that does not require to be initially loaded})
a little improvement, yet I am not satisfied. What if I want to call certain functions for a certain page only? are there ways to accomplish this? and I am really disgusted at how my $(document) gets really huge when I am using a lot of plugins.
How do you go about writing your functions in jquery?
I'd suggest at least namespacing things to ensure you don't pollute the global namespace. For example:
var myNameSpace = {
a: function(){//a function that applies plugin to an element},
b: function() {// another function}
};
$(document).ready(function() {
myNameSpace.a();
});
The main benefit is that you're able to compartmentalize your code into logical units of work which focus on specific tasks. It'll make code organization substantially easier.
Rebecca Murphey did a wonderful write-up on this topic which you can read here: http://bit.ly/6og36U
You can also separate your JS into their own unique files and write a routine to leverage jQuery's getScript() method to load the necessary files on-demand (http://docs.jquery.com/Ajax/jQuery.getScript). The key would be to determine the dependencies in your script and load the .js file at the appropriate time.
I recommend having one Javascript file for the whole site. That file should only contain functions:
function a() { ... }
function b() { ... }
The reason is that with one file it gets cached once (if done right) and that's it. And then using inline JS on each page I put:
$(function() {
a();
b();
});
I haven't really found a need to have multiple ready() calls.
The reason for this is efficiency. You don't want to be executing unnecessary Javascript and what's why the external JS file actually does nothing but include functions that you can call. Then each page only calls what it needs. Plus you can easily find it by just looking at one place (the page).
You might try to split your functions into multiple files and include just those which are needed for each page. In each file would be separate $(document).ready(function(){ ... });
I think there are two ways of achieving this:
A: split JavaScript into several files. (One library file and each with the side - specific code which also call the ready function.)
B: make one file with all the JavaScript and then some inline JavaScript file like this:
var tasksToRun = [ function_a, function_b,...]
In your library JavaScript you check for the global var and execute each function referenced in the array.
In my apps I tend to write all the functions for a given section of the app in within a closure to avoid namespace issues.
Something like this:
(function($) {
function a() {
// stuff
}
function b() {
// stuff
}
// ...
$(function() {
// invoke dom ready setup methods here
});
})(jQuery);
This has a bonus of letting my code be usable in other pages that may be using prototype or other js libraries (in large webapp with many devs like the one i work on, it's important to keep the namespace clean).
I generally only have one ready call per file. That call is responsible for setting up all the related things in that file. This allows each file to sort've act as a "library": developers that want to use the functionality just have to include it on the page and add the appropriate markup and the functionality will set itself up.
I admit I copied this layout from the way several jQuery plugins are built.
I like cletus' suggestion of a single file, but only when the app isn't too large. It starts to be difficult to maintain if you have too many things within a single file.
Related
I have 2 simple coffee scripts and assets pipeline. I obtained:
(function() {
window.App.Test_widget = {...}
}).call(this);
(function() {
$.widget("ui.Test_widget", window.App.Test_widget);
$(document).ready(function() {...});
}).call(this);
but I want 1) merge closures 2) add closure parameter
(function($) {
var App;
App.Test_widget = {...}
$.widget("ui.Test_widget", App.Test_widget);
$(document).ready(function() {...});
})(jQuery);
I cant google a way of implementing this
UPD:
1) I dont want to place each file in different closures. I want to control this
2) I dont want to put anything in window if it is possible
ANSWER is simply: "use bare option. for sprockets see commit"
If you want that level of fine-grained control over output, you'll have to write your JavaScript yourself rather than allowing CoffeeScript to do it for you. I say that as an advocate of CoffeeScript: If you use it, you have to accept certain conventions that go along with it, such as the wrapper that gives each file its own scope. You lose the freedom to concatenate files however you want in order to share variables across files.
It's worth mentioning, however, that
In CoffeeScript 1.2.0+, the wrapper is added only when necessary. At least in your first file, that's not the case. (Edit: I was mistaken about this; this feature existed in 1.1.3 but disappeared before 1.2.0)
Writing $ = jQuery at the top of a function is semantically equivalent to having an argument named $ and passing in jQuery as the value of that argument. So you need only put $ = jQuery at the top of each of your CoffeeScript files in order to use jQuery in noConflict mode.
I think what you're describing is a deferred...you want to do something after your two closures finish? If so then look into jQuery 1.5 deferred infrastructure.
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?
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,
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:
There's clear association of what JS behaviours happen where
You get rid of inline Javascript in pages – I dislike it if only because it makes setting JS breakpoints a chore
If you combine your JS libraries, you only include 2-3 script files on any given page, of which only one isn't reused on every single page
Less risk of conflicts where a selector that's too broad could match elements on a different page than it was intended to and attach unintended behaviour to them.
The JS code is still reasonably straightforward - scripts included on pages. No need to devise a module structure.
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.
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
If it's goint to be a large web project then i would recommend you Backbone.
We have lots of javascript functions, which are usually handled via the onclick function. Currently they are present in every file where-ever it is needed. Would it make sense to consolidate all javascript functions into a single file and use this where-ever it is needed? What is the general practice here
<s:link view="/User.xhtml"
onclick="if (confirm('#{messages['label.user.warning']}')) {
var f = $('user');
f.method = 'POST';
f.action = f.submit();
} return false;">
Yes! Absolutely factor this out into an external javascript. Imagine if you needed to change something in this code. How many places do you have to change now? Don't duplicate code. It must makes your page bigger, which obviously affects how much is getting downloaded.
It's up to you to determine where the reusability lies in your own code. But it's easy enough (and a good idea) to create a library of often-used functions. Create a file like mylib.js, for instance, with things like...
function saveUser(f)
{
//...
f.method = 'POST';
f.action = f.submit();
}
add this to your pages:
<script type="text/javascript" src="mylib.js"></script>
add code your events like this:
<s:link view="/User.xhtml" onclick="return saveUser($('user'));">
Notice that the library code avoids any dependencies on the layout or naming of elements on the pages that use it. You may also want to leave little comments that will remind your future self what the purpose and assumptions of these library functions are.
Would it make sense to consolidate all javascript functions into a single file and use this where-ever it is needed?
Ummm...yeah
It would be better to do something like this:
function saveUser() {
// logic goes here
}
and use the markup
<s:link view="..." onclick="saveUser();">
Using code inline like that is very bad. Don't do it. Or the prorgamming gods will grow restless.
It is always a good idea to put JavaScript code in JavaScript files. Like you don't mix content and presentation (XHTML and CSS), you don't have to mix content and interactivity (XHTML and JavaScript).
Putting JavaScript code in a separate file has several advantages:
No need to duplicate code (so better reuse),
Possibility to minify the source code, thing which is quite impossible to do if you put together XHTML and JavaScript,
Ability to use non-intrusive JavaScript, helping to create more accessible websites (there is probably nothing wrong from the accessibility point to use onclick and other events, but it becomes very easy to forget that the website must work without JavaScript, thus developing a non-accessible website).
Better client-side performance: larger pages make things slower; when you put JavaScript outside, the pages are smaller, and the .js file is cached by the browser instead of being loaded on every request.
Javascript can be accessed via a script tag, which can point to an external script or define it for use in this document only.
<script type="text/javascript" src="mycustom.js"></script>
<!-- OR -->
<script type="text/javascript">
function saveUser(username) {
//code
}
</script>
No offense, but if you didn't know that you are either very new at this or you skipped a lot of steps in learning javascript. I recommend going through the w3schools.com tutorial on javascript and anything else you'll be using.
I am currently using jQuery to write an online application, that started off with a couple of lines of code, and have quickly now become over a 1000 lines.
My code's structure is simple. I have a window.load which wraps my javascript, and inside it I start adding my click event handlers, and the various functions that makeup my application.
$(window).load(function(){
// Code goes here...
});
My code functions can definitely be grouped into categories; e.g. 5 functions perform animation, 12 are event handlers, etc.
I would like to group the functions in their own js files, and import them individually. I can later use my CMS engine to concatenate and compress the files on the fly.
What is the best way in doing so. I am thinking that maybe I can give some of my functions their own namespace for further clarity; e.g. all animation functions are prefixed with ANIMATION - ANIMATION.moveDiv1(), ANIMATION.moveDiv2, MYEVENT.div1Clicked, etc.
I generally stick all related items into their own file, with a namespace that matches the file for readability sake.
An example file could look like:
Example.js
var Animation = {}; // create the namespace-like object
Animation.moveDiv1 = function() {...};
Animation.moveDiv2 = function() {...};
There's really a lot of ways to do this. Speaking of compression, there are some nice tools that you can use to compress things. Check out YUI Compressor
Modularity is a good goal with Javascript, but I would say the next level would be to actually use some Javascript OO techniques. If your app is simple enough, you can probably do without it though.
Your code files should mirror your classes.
Your classes should follow principles of good OO design.
In terms of load-time within the browser, kekoav and knut have the right idea - just use YUI or another script compressor/minifier (and optionally an obfuscator), combine them into a single file and load them all from a single script include directive.
I'd also have a look at JS the prototype property of your classes - if they're getting large and you're creating multiple instances of them, you'll start to see significant performance gains by putting your public (and optionally, private/privileged) methods into the class prototype.
You should definitely be using fully-qualified namespaces for your classes, either using Microsoft's Type.registerNamespace if you're using their AJAX solution, by declaring your own namespace functions as per kekoav's post, or using a squillion other similar approaches that Google will offer.
Good idea from a standpoint of application management, bad idea from the standpoint of loading time. The browser has to load all those little scripts synchronously, therefore taking more time for each additional script you want to load. That's not including the main jQuery library script, the jQuery UI and whatever else you plan on having in your document. Test both premises: abstracting functions out into their own individual scripts and load them vs. one big script that only requires one call to load. Take it a step further and minify the "one big script", one more step and make sure it's served as a compressed file.
You may split the JavaScript files into classes when you are developing, but you should combine your scripts, and minimize them in a production environment. Please take a look at YUI Compressor for more information.
When developing JavaScript, I tend to separate JavaScript code out into different files and then run a script to concatenate the files and compress or pack the resulting file. In the end, I have one file that I need to include on my production site.
This approach has usually worked, but I've started to run into a problems with prototypal inheritance. Specifically, if one class inherits from another class, the file for the parent class needs to be included already for the inheritance to work. If the concatenation script I'm using is simply concatenating a directory full of files, the child class might occur in the code before the parent class. Like this:
parent_class.js
var Namespace = Namespace || {};
Namespace.Parent = function () { };
Namespace.Parent.prototype.doStuff = function () { ... };
child_class.js
var NameSpace = Namespace || {};
Namespace.Child = function () { ... };
Namespace.Child.prototype = new Namespace.Parent();
The only way this works is if parent_class.js is included before child_class.js, which might not happen if the concatenation script places the child code before the parent code.
Is there a way to write this code so that the functionality is the same, but the order in which the code is written no longer matters?
Edit: I forgot that I'm using namespaces as well, so I added that to the code as well, which might change things a little bit.
When I've worked on large apps, I've use requireJS to divide my code into modules, and make sure those modules are loaded in the correct order. Then I just mark my derived class as depending on the parent class.
RequireJS comes with a tool that will combine and minify all your modules for production deployment as well.
If the concatenation script I'm using is simply concatenating a directory full of files, the child class might occur in the code before the parent class.
Is it too simple a solution to prepend a sort order value to each filename, and sort by name before performing the operation?
eg:
01_parent.js
02_child.js
Otherwise, perhaps maintaining a preordered list of files in a separate file. Maybe even go one step further and provide a hierarchical dependancy structure in xml to parse? This might be over-engineering the solution a bit :-D
Some options for ways to deal with the problem if you had no way of determining how the javascript files are written.
I suppose you could do something really hackish like this:
setTimeout(function() {
if(typeof(Parent) != "undefined" && typeof(Child) != "undefined") {
Child.prototype = new Parent();
} else {
setTimeout(arguments.callee, 50);
}
}, 50);
That code could also be anywhere, and would continually run until both the Parent and the Child were loaded...But I wouldn't do that.
Personally, I would just make sure your files are combined in the correct order.
If the objects are "namespaced" then you either have to switch to a build solution that incorporates in-order concatenation or use something like dojo.require (but obviously not dojo specific). Basically you want a framework that will provide you with the ability to check if a given identifier is available and pause execution and include it (via evaled ajax or an inserted script tag) if it isn't.