5 Tips for Better jQuery Code

I've been coding using jQuery since shortly after it came out, and well -- I've been using it almost every work day. Here is a few tips that have saved me time.
#1: Use data method instead of storing data inside the DOM.
The mistake I see people making all the time is this:
JavaScript:
$('selector').attr('alt', 'this is the data that I am storing'); // then later getting that data with $('selector').attr('alt');
Why is this a bad thing? Because "alt" has absolutely no meaning whatsoever, as well as HTML is not meant to store data.
Instead use the data method in jQuery. It allows you to associated data with an element on the page.
JavaScript:
$('selector').data('meaningfullname', 'this is the data I am storing'); // then later getting the data with $('selector').data('meaningfullname');
This allows you to store data with meaningful names and as much data as you want on any element on the page. It is a really amazing utility and something I've come to rely on.
#2: Take advantage of jQuery's built-in custom selectors.
jQuery has a plentiful amount of selectors that are beyond basic CSS selectors, so use them. Some that I use are:
:inputexample: get all the inputs on the page regardless if they are checkbox, textarea or select list - use:input[attribute=value]example: find an input with the name, "container" - useinput[name='container']:eq(index)example: get the fourth table on the page - usetable:eq(3)
#3: If you are Manipulating the DOM a lot, use livequery.
Note on March 21st, 2009: New in jQuery 1.3, the live method has adopted many of the same events of livequery into the core of jQuery.
Note on November 16th, 2008: If you understand event delegation, use it as an alternative to using livequery for attaching events.
When you add elements to the page a lot, attaching events to them and running functions on them then use Brandon Aaron's livequery plugin. This way you can do things like:
JavaScript:
$('div.edit').livequery('click', function(){ //go into edit mode });
Then whenever you add a div to the page with class "edit" it will attach that click event. This works for all other events, as well as if you want to run a function on an element right when it is added you can do this:
JavaScript:
$('span.flag').livequery(function(){ // run this function when a span with class "flag" is added to the page });
#4: Use jQuery form plugin to submit files via Ajax.
If you use Mike Alsup's jQuery form plugin you can use it to submit files via Ajax. It uses a trick with an iframe to submit the data. Just put in an input type file, then use $(form).ajaxSubmit(); and you are good to go.
#5: Use classes as flags.
If you aren't storing data, but need to set a flag on an element use a class. What do I mean by a flag? Well, for instance if you are in "edit mode" of a form you might use the class, "editing". With jQuery you can add a class with the addClass method and then check later if an element has the class with the hasClass method.
Comments
:eq(index) has definitely come in handy many times, but I remember it took a little while for me to find it.
I can't even begin to count the number of times I've been asked, "Why don't my event bindings work on newly added DOM elements?" I usually point people to the jQuery FAQ entry explaining it (which also suggests livequery()).
datamethod, so you are definitely not alone on that one. That was why I wrote these tips - I understand people know what they are doing, but some parts of the jQuery API are undiscovered by most.The tip with using classes as flags is something I need to reconsider, thanks! Keeping flags as javascript variables is easier on the eye for me as you don't need to refer to DOM to do anything, but perhaps the added benefit of trying do bigger things with "conditional" CSS might be worth giving it a shot.
Did you use $.data() in the Google Maps mashup you demoed at jQuery Camp?
hasClassmethod in jQuery to check for the flag.Tom Sieron: Normal JavaScript objects and variables are great for storing things! The only reason you would ever want to use the
datamethod is if you want to associate a piece of data with a specific element on the page.Sean O: no I didn't use data the method. That was just a simple demo, but you reminded me I really need to finish that tutorial!
[attribute=value]is a custom jQuery selector, while it's actually defined in the CSS2 specification (http://www.w3.org/TR/CSS2/selector.html#attribute-selectors).Imagine you need to pass many divs per records in a DB, and do operations with each div. How you say from backend to jQuery/javascript which ID is related to current div?
I'll give livequery a try, looks very useful.
Thanks
Many thanks for the .data() method - it looks very useful and, like the rest here, it has eluded my attention until now.
A question about its performance: where is the data actually stored? Are we bloating the DOM by adding large data elements to it, or is the data being stored in js variable space as say an associative array and cross-referenced by the element ID?
I have some reservations about using classes as flags. While I do use this technique a lot, it has always bothered me that my HTML markup will not pass a lint test what with all those missing classes. E.g. in Visual Studio the elements that are so adorned with these undefined classes don't fall easy on the eye, yet I've never bothered to define dummy CSS classes to get rid of the warnings. I've always assumed that there would be a more standards-compliant way of achieving this ... but I'm not so sure anymore now that one of my jQuery heroes is advocating this technique!
Visual Studio barks if you don't have any styles associated with the flag class. Just try adding a few flag classes to the style sheet and the errors will go away. As far as standards, if it helps you and makes sense to developers than who cares? To me classes are meant to be CSS flags, why not use them for JS flags as well - it makes perfect sense to me.
One thing I've been doing that (to me) might be a good thing to tell people about is not to reference the same deep selector call multiple times. Calling $(this).parents('.parent').find('span') more than once in your function is probably not the best way of going about it as you're relying on jQuery to query the DOM each time to find the handle to what you're looking for. What I like to do is set a long selector query like that to a JS variable, and then work off that variable so it doesn't have to be calculated all the time. Same thing as setting a counter variable before your for loop so you only have to do it once.
var el = $('p.secondary');
el.css('color','#cecece');
el.text('hello world!');
el.append('
Another paragraph
');Instead of constantly referencing the element, $('p.secondary'), set it to a variable which "caches" it locally for quick reuse. Immensely efficient!
@Jahdur Rahman: Try this link: http://docs.jquery.com/Plugins/livequery
They only understand it when they face performance problems on large dom operations.
I think it is much much more productive to teach people event delegation, rather than orientating them toward a pseudo-miraculous solution that will badly leak when thing get serious.
Event Delegation rules !
It is true that Event Delegation is a powerful technique, but it also needs to be approached with care. In most cases, it can be used for relatively infrequent events (such as clicks) with impunity, but more frequent events (such as mousemove, mouseover) can see very poor performance. Event Delegation requires inspecting the target of each and every event (of a particular type) that is fired. If that event is a mousemove, you can be performing a ridiculous amount of target inspections.
Bottom line is to understand the implications of all these techniques so that you can pick the best one for your current needs. Factors such as the frequency of DOM modification and the type of events you're reacting to can make a world of a difference.
Can the 2nd parameter for data() be any type of variable, or does it have to be a string?
set function in data with
$(selector).data('foo', function(){ alert('bar'); });$(selector).data('foo') ... returns function()$(selector).data('foo')() ... alerts 'bar'set object in data with
$(selector).data('foo', { 'a':'b', 'c':function(){ alert('blah'); } });$(selector).data('foo').a ... returns "b"$(selector).data('foo').c() ... alerts "blah"Wow, data() seems to have struck a chord. Prior to discovering data() I was using the attr() function to add data to elements. As with data(), attr() can also be used to add arbitrary objects to elements. Obviously adding attr("class") to an element is going to have some potentially serious side affects whereas data("class") won't but it is possible to add arbitrary attributes to HTML elements, i.e. you don't have to repurpose valid HTML attributes such as "rel" or "alt". I'm sure there are many opinions as to the efficacy of such an approach.
I guess my concern is more about whether either approach represents a good practice. Adding some data to an element in one module and accessing that data from another results in coupling so I would use it sparingly and only within a single module.
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=302090867&mt=8
Looks like there's also a CSS Cheat Sheet from the same guys.
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=301093674&mt=8
I suppose I built something rather similar to it though, as I have had .js classes representing the logic and data storage of the application, with an array of references to appropriate DOM elements for each of the objects. In essence, every DOM element would be represented by an object. Just had to ensure that when I stringify the objects into JSON for storage in a database that all the references to DOM are removed. Took a while to put together but worked well; I'm sure I could have slashed the development time by half had I used jQuery though.
Personally, I find this type of article a lot more useful than others that only touch surface of great effects.
I especially like the point on event delegation and livequery.
Greetings from DE
Thanks Marc, you're on my RSS reader now :)
Nice article! :)
I've been using jQuery at big commercial companies for a few years now and although everyone likes to use it not many project path decision makers ever seem to be all that concerned with really using it well as much as they just want the project out the door quick.
So I appreciate this tight concise list as it gives me a few more paths to get to the finish line that will undoubtedly help shed min/hours off future projects.
I like your points.
Add this too :
// Checking the element type of the selected element, eg;
if($(this).is('form')){
//welcome
}
else{
throw new Error('This block works only with a form');
}