// September 29th, 2010 // 3 Comments » // JavaScript, jQuery
jQuery is an awesome JavaScript library that simplifies cross browser client side scripting especially DOM traversing, AJAX development, event handling, etc.
If you are reading this article, chances are that you have already used jQuery at some point of time. If you haven’t, stop reading this right now. Open up a new tab. Go to jQuery.com and download it. Play with it. That’s the best way to learn it.
Now, back to our topic. I obtained most of my jQuery skills on a project that I’ve been working on for the last couple of years. While I enjoyed the experience of discovering new things and learning it on-the-go, I must admit that I have written pretty bad code without knowing how badly JavaScript sucked.
Good news is that, I’ve learned quite a bit during that process. Not just about jQuery but also about DOM, CSS, JS, hidden cool features of Firebug, JSON, XHR etc. And better news is that I’m about to share some of that knowledge with you in a moment.
In this article, we’ll talk about little things you can do to your jQuery code that will improve performance and also improve readability and hence, maintainability.
You can download the source from here.
Anyways, here we go. Code and explanation follows.
1. Chaining
Let’s take a look at the following code snippet.
$(document).ready(function () {
$('#testControlId').css('color', 'red');
$('#testControlId').click(function () {
$('#testControlId').text('Google!');
alert('Text of this link has changed to : ' + $(this).text());
});
});
While it’s a perfectly functioning code, it has a couple of issues. For one, it’s a little more verbose than it needs to be. Two, it forces JavaScript to go look up the control by the id “testControlId” every single time it is referenced, which can add up eventually and cause the page to crawl.
Note that most of the jQuery methods returns a jQuery object and in this case, it means the control represented by “testControlId”. So let’s see how we can rewrite the code above.
$(document).ready(function () {
$('#testControlId')
.css({
color: 'red'
})
.click(function (e) {
$(this).text('Google!');
alert('Text of this link has changed to : ' + $(this).text());
});
});
Does that make sense? “.css()” function returns a jQuery object that can be worked on instantly. So we use it right away to set the other properties like to hook up the click event handler.
2. Caching
Caching is a great way to limit the number of times we need to traverse the DOM to find elements matched by the selectors. Here’s an example.
var anchors = $('a');
anchors.click(function(){
anchors.addClass('cacheClass');
});
So when would you use caching as opposed to just chaining? Use chains when there is relatively lesser amount of things to do with the object. In other words, if the chain gets too long to the point that it compromises readability, then it’s better to cache the element using a variable and work with that. Remember, whenever you use chaining, proper indentation and line breaks are necessary to make your code readable and maintainable.
3. Event delegation
Let’s say you have a requirement to write code to change the background of a table cell when the user hovers over it. Here’s one way to do it.
$('#testTable td').click(function(){
$(this).css('background', '#ECE9D8');
});
Do you see the problem with the code above? What happens when you have a 100 rows in the table, each with 10 cells ? This code will bind 1000 events to the table. Seems inefficient, isn’t it?
A better way to do the same thing is to just attach a single event to the table, so that when the user clicks anywhere within the table, the event handler can figure out which cell was clicked before turning it’s background color to ‘#ECE9D8′. That’s what the following code does.
$('#testTable').click(function(e) {
var clicked = $(e.target);
clicked.css('background', '#ECE9D8');
});
Another advantage of this code, is that if you add new rows to the table after the initial DOM load, the handler would still get fired even for the new cells.
4. Save data using Data()
jQuery actually provides a method to store data in DOM. So instead of trying to incorrectly use some of the unused attributes like title, alt etc. to save data as Key-Value pair, you can do it as follows.
//Set the value
$('#testControlId').data ('someKey', 'someValue');
//Get the value
$('#testControlId').data ('someKey');
5. Custom selectors
What if the built-in selectors in jQuery is not doing it for you? What if you want to select elements in the DOM using some filters that don’t exist out of the box? You can write your own custom selectors to do that. Take a look at the code below.
$.extend($.expr[':'], {
withEmptyHREF: function (a) {
return $(a).attr('href') == '' || $(a).attr('href') == 'undefined';
}
});
$('a:withEmptyHREF').css('color', 'green');
What this code does is, go find all the anchor tags whose href is not set and change the color to green. Obviously, this is a very simple example. But as you can imagine, this feature has the potential to do a lot of powerful stuff.
6. Use Context
Instead of starting from the DOM root, it looks for the elements matching the selector in the Context provided as shown below.
$("a.someAnchorClass", "div.someClass");
This significantly cuts down on the time it takes to find an element because we have narrowed down the look up area to the div of type “someClass”. So now, it looks for the anchor tags with class “someAnchorClass” only in that div.
7. Live() Vs Click()
Live() will bind a click handler to all elements matching the selector in the current DOM as well as all new elements (that matches the selector) added to the page later. For example,
$( "a" ).live(
"click",
function( event ){
doSomething($(this));
}
);
Click() will bind a handler to all the elements matching the selector in the current DOM. Period. It doesn’t hook the handlers up to the matching elements that get added later on. Here’s an example.
$('a').click(function() {
doSomething($(this));
});
8. Length() Vs Size()
What if you need to find out if there are any div elements whose class is set to ‘hidden’ in the DOM? That’s when you use the jQuery object’s length property as follows:
if( $("div.hidden").length ){
//You'll get in here if there's at least one div of class "hidden"
}
Guess what? You can use the Size() method to do the same thing. So what’s the difference?
Size() method uses Length() internally. So essentially, you’ll be skipping one layer if you use length() directly and hence, performance will slightly faster.
Here’s an example of Size() function.
if( $("div.hidden").size ){
//You'll get in here if there's at least one div of class "hidden"
}
9. Partial Page Refresh
If you want to refresh just part of the page, specifically just one control, then here’s how you do it.
$(document).ready(function() {
setInterval(function() {
$("#testControlId").load(location.href+" #testControlId>*","");
}, 3000);
});
This may not necessarily replace iFrames (ugh!), Ajax calls etc. But it can be very useful when you have widgets on a page that need to be refreshed without reloading the entire page.
10. Disable right click
This may sound a little silly at first. Why would you want to disable the context menu on a page, right? But think about this. What if you have to add some custom menu of your own to provide certain features? In that case, the browser’s context menu may be obtrusive, yeah? So here’s how you remove it.
$(document).bind("contextmenu",function(e){
//Add code for your own custom menu if necessary.
//And now, cancel the default context menu
return false;
});
Conclusion
jQuery is one of the best things that has happened to web development in the last few years. Suddenly, developers do not loathe JavaScript anymore.
Learn it. Embrace it. Join the cool kids club.
Happy Coding!