Learn with our tutorials and training

developerWorks provides tutorials, articles and other
technical resources to help you grow your development skills
on a wide variety of topics and products. Learn about a specific
product or take a course and get certified. So, what do you want to learn
about?

Featured products

Featured destinations

Find a community and connect

Learn from the experts and share with other developers in one of our
dev centers. Ask questions and get answers with dW answers. Search for local events
in your area. All in developerWorks communities.

Advanced jQuery

Turning a good app into a great app

Michael AbernethyPublished on July 14, 2009

This series on jQuery
has taken you far in your abilities to create a JavaScript-based Web
application. Even if you had never heard of jQuery before you started reading
these articles, by now you should have all the skills and background in the
language to produce a good Web application using jQuery. However, sometimes a
good application is not enough. Sometimes you need a great Web application.
This requires a few extra steps, steps you add
to your application to ensure it runs smoothly in big apps and small apps and
looks just right to every user. They are the last layers of polish you add to
make your Web application sparkle.

In this article, I'll discuss performance-based improvements to your code, but I'll
also talk about things in the jQuery library that some people may gloss over.
These items are important in complex applications, they are plug-ins that are vital to anyone's
applications, and they are nice design tips to make your Web apps easier to code.
Finally, in the last section, I'll talk about some of the new features in
jQuery 1.3, which was released recently and added a few new features to the
library.

The first sample
application

Most of the tips in this article can be
found in the sample application attached to this article (see Downloadable resources), which is a
straightforward e-mail Web application. It should look familiar as it's the
same one that I presented in the first article in the series. However, you
should see how far it has come from the first article, how the performance has
been improved, and how the final layers of polish to it has turned it into a
really great Web application.

Figure 1. The example
application

Bind/Unbind

In the Events module, there are two functions, called bind() and unbind(), that appear on the surface to duplicate the efforts of
all the other event methods. After all, if you can simply attach a click() method to a page element, why would you need
to call bind("click") on it instead? It's just a
waste of keystrokes. Well, it turns out that these functions come in handy in
certain situations, and when used correctly they can drastically increase the
performance of your application. These functions do give you the ability to
attach events to certain page elements, just like the numerous event methods
in the module, but they also allow you to remove these events from the page
elements. Why would you want to do this? Well, let's take a look at the Web
application and see how they can be used in this situation.

This
code should look relatively straightforward, as it's pretty much the same
widget I've worked on in a few of the articles. You saw the
"select/deselect all" widget in the first article where I showed it in its
basic form. In the performance article, you saw how to improve its
performance by caching your selection queries and minimizing your usage of
searching by CLASS. However, there's still a problem. When the
"select/deselect all" checkbox is pressed in a table with 100 rows, you see
very poor performance. In fact, on my browser, with this code in place, the
average time to complete the select all was 3.4 seconds. That's not very
responsive at all. Even after all of the optimization to this point, you still
have something that's not acceptable.

Let's go one step deeper
in the algorithm here and see if something is amiss. You're looping through
every checkbox on the page and seeing if it's current "checked" status is the
same as the "select/deselect all" checkbox. If it's not, then you're calling
"click" on it, to make it match the state of the "select/deselect all"
checkbox. Wait a minute though... you also attached a function to these
checkboxes, so that with each click, you're calling the changeNumFilters() function. Upon closer examination, you've set up
an algorithm that calls the changeNumFilters() a
possible 101 times. No wonder the performance was so bad. Obviously, you don't
need to update the count of selected messages with each click, you can do it
once at the end of the process. How do you prevent this method from getting
called, while at the same time clicking the checkbox?

Well, of course,
the unbind() method is where this comes into play.
You probably saw this coming. By calling unbind()
before the checkbox is clicked, it will stop the call to click() from in turn calling the changeNumFilter() method. This is great! This is what you wanted.
Now it won't be called 101 times. But, of course, this would only work once,
so you must attach the click method back to each checkbox after you're done
calling click on it, using the bind method. See the updated version in Listing
2.

With
these optimizations, you have gotten your checkbox to run in approximately 900ms, which
is quite an improvement in performance. It was all from taking a step back and
thinking about exactly what your algorithm was doing, and how your actions would
trickle through the code. Instead of calling a function 100 times, you can
simply call it once. Hooray! After looking at this function for this many
articles, you have finally made it as fast and efficient as possible. Well, not
really... It turns out there's a super-fast way of running this algorithm that
I've been holding back from you until now. Besides, if I had given you the
fast algorithm right away, I wouldn't have been able to use this function as a
lesson for these articles. Hopefully, this situation has opened your eyes
to the benefits of using the bind/unbind feature in your code (if there's no
shortcut of course).

Remember: Use the bind/unbind in situations
where you don't want the default event to fire, or as a way to temporarily
attach or remove events from page elements

Listing 3 shows the
super-fast way of writing this algorithm, if you have this widget in your own
code. It runs this function in 40 ms, blazing fast compared to the other
ones we've tried.

Listing 3. Widget with super-fast algorithm

Live/Die

Two of
the great new additions to the 1.3 version of jQuery are the live() and die() functions.
Their role in a well-designed Web application can best be seen through an
example. Imagine attaching a double-click to every cell in a table. As an
experienced jQuery veteran, you know you should create this setup in your
document.ready() function, like shown in
Listing 4.

Listing 4. Setting up a double-click

There's
only one problem with this design. Yes, it attaches the double-click event to
every row in the table with a class of messageRow.
But, what if you add new
rows to the table? For example, those rows might appear when you have an
additional message that gets loaded into the page using Ajax without a page
reload. This presents a problem, because the code, as written, won't work. The
event you created was bound to all the existing tr.messageRow elements that were present when the page loaded. It's
not bound to any new tr.messageRows you create during the page's lifetime.
People who write code like this would be disappointed to discover that their
code didn't work. Beginner jQuery programmers may even spend a few hours of
headache-inducing debugging trying to figure out why their code isn't working,
before stumbling upon this fact in the jQuery documentation. (Yes, that was me
last year).

Before jQuery 1.3, there were three ways to get around this
problem, none of them elegant (for those of you who continue to use jQuery
1.2.x, these are still valid). The first was the re-initialization technique,
which simply reattached the event to the selected elements each time a new one
was added. The second was taking advantage of the bind/unbind methods, which
we saw in the previous section. See them both in Listing
5.

Neither
of these techniques were very elegant though, as you can probably tell. You'd
be repeating code. And, you'd be forced to find all the possible spots that a new
page element could be added to the page and deal with the "hot element"
issue at that point. That's not a good way of programming. Besides, this is
jQuery. It's supposed to make everything incredibly easy for us. It's supposed
to do everything for us.

Luckily, there was a plug-in that seemed to
solve these problems. It's called the LiveQuery plug-in, and it allowed you
to bind certain page elements to events, but to do so in a "live" fashion, so
that all page elements, including ones that existed at page creation and ones
created during the page's lifetime (through Ajax calls for example), would trigger
the event to occur. This was a very clever and important plug-in for UI
developers, as it made working with dynamic pages as easy as working with
static ones. For a Web app developer, it was really one of those "must have"
plug-ins.

The jQuery core team agreed so much in the importance of this
plug-in that they incorporated it into their 1.3 release. This "live" feature
is now a part of the core jQuery, so any developer can take advantage of the
function. The plug-in is almost exactly duplicated in the 1.3 core code,
minus a few events that didn't make the cut in the first release of 1.3. I'd
bet some money that these missing events will appear in one of the next
releases of jQuery. Let's take a look at how it can be used to change your code.

Listing 6. The "live" event model

Making this small change in the code, all
tr.messageRow elements that are on the page will
trigger this code when double-clicked. This is not the behavior you'd see if
you simply used the dblclick() function, as I've
explained above. For this reason, I highly recommend that you think
about using the live() method for most of your
event methods. In fact, I'd say it's a must that any page that creates page
elements dynamically, whether through Ajax or user interaction, must use the live() function instead of the alternative event
methods. It's just such a great trade-off between ease of coding versus. possible
bugs, that it's a no-brainer decision.

Remember: Always use the
live() method when attaching events to
dynamic page elements. This makes your events as dynamic as your page
elements.

Ajax Queue/Sync

The usage of Ajax calls to the
server is becoming the measure by which Web 2.0 companies measure themselves.
As we've discussed endlessly here, using Ajax in jQuery is as simple as
calling a method call normally. This means you can call any server-side Ajax
function as easily as you would a client-side JavaScript function. This bonus
has some less than desirable side-effects though, and these can occur if there
are too many Ajax calls to the server. If a Web application is going
overboard with Ajax calls, problems can certainly arise.

The first
problem is that some browsers limit the number of open connections to the
server. In Internet Explorer, the current version allows only 2 open
concurrent connections to the server. Firefox allows 8 connections, but it is
still a limit on open connections. If a Web application is making Ajax calls
out of control, it can certainly have more than 2 open connections, especially
if the server-side call is time-intensive. This problem can arise from bad
design from the Web app designer, or even a user who is out of control with
their requests. In any case, it's not a good state to be in, and you don't
want to
be in any situation where the browser is deciding what connections it will
allow and which ones it won't.

Further, because the calls are
asyncronous (the "A" in Ajax), the returns from the server are not guaranteed
to be in the same order you sent them. Wait....what? Yes, if you make 2 Ajax
calls at about the same time, you aren't guaranteed that the responses from
the server will come back in the same order. Thus, if your second call depends
on your first one finishing first, you may be out of luck. Imagine a scenario
where your first call retrieves data, and your second call manipulates the
data in some way on the client-side. If your second call returns faster than
your first Ajax call, your code may lead to errors. You have no way of
guaranteeing the response speeds. Multiply this issue by 4, and you can see
problems start to arise quickly.

The creator of jQuery recognized this
as a potential problem, but also recognized that it was only going to be a
problem for Web applications about 1% of the time. However, for those
developers who are in the 1%, they need a solution. He created a plug-in that
can be used to sort through this problem, by creating an Ajax Queue, and an
Ajax Sync. Both are very similar in how they function: the Queue places Ajax
calls one at a time, waiting for the other to return before starting the next
one. The Sync sends them out immediately, but only returns to the calling
function when the previous one has already returned.

This solves the
overload problem by controlling the Ajax calls on the client side, and also
controlling and regulating how the responses are sent back to the client-side
code. You can now be sure you know the order in which responses come back to the
client, enabling you to write code that can predict the order of events. Let's
take a look at how this plug-in works, and how you can use it in your code with
the example in Listing 7. Keep in mind that this is designed for the 1% of
conditions where multiple Ajax calls have vital information dependent on
previous Ajax calls. This example is not one of those examples, but it
nevertheless lets you see how the plug-in can be used (it would be difficult to
create a good real-world example where this plug-in is needed and still have it
be easy to understand).

Remember:
If your application has multiple Ajax calls that can overlap each others'
functionality, look to use an Ajax Queue or Ajax Sync.

Second example Web
application

I will use another widget to address the final 3
things in this article, and I want to show it off and explain it before I
delve into the code behind it. It's the familiar 401k widget, the one you saw
in one of the previous articles (see Related topics for links to the articles). However, there is a subtle difference this
time around, because I've included the widget twice on the same page. It's
attached to two separate tables. That brings up several interesting points.
Figure 3 shows what the widget looks like:

Figure 3. 401k
widget

In this widget, I am doing a few things. The first is totaling the
textfields and determining if they collectively add up to 100. If they don't
add up to 100, I display an error indication to the user that they
haven't used the widget correctly. Second, I sort each of the choices after
each choice receives input. In this manner, the investment allocation with the
highest percentage will always "percolate" to the top of the table. You can
see this in Figure 3, which shows the choices sorted numerically by
percentage. Finally, to make it look cool, I'll add some stripes to it.

The HTML code to produce this widget is surprisingly spartan. Listing 8
shows it is in its entirety.

Setting up widgets in
jQuery

That little bit of HTML leads directly into this section,
which centers on the idea of setting up widgets, and all the code that they
need, within the jQuery code itself. You're obviously used to doing this when
you attach events to things, and for simple things like attaching classes in
certain situations. For some, though, this is taking it a step further. All of
the setup code for these widgets is going to be in the jQuery code itself. I
can give you all the usual mumbo-jumbo about separation of roles, letting the
HTML designer do his work and the JavaScript coder do his, but you've all
heard that a million times already. I'll just add one other thing here, and
that's the idea of "class decoration," which so many plug-in authors have taken
to using as well. Looking at the HTML code in Listing 8, by simply attaching a
percentSort class to the table, you can transform the entire functionality
and look of the table. This is really the goal of any widget you design, to
make the addition and removal of the widget as simple as adding a class to it.

Let's go through several of the steps I've used to setting up the
widgets in jQuery. By looking through these steps, you can begin to see how
this design pattern emerges in Listing
9.

Listing 9. jQuery widget code

$(document).ready(function() {
// the first step is to find all the tables on the page with
// a class of percentSort. These are all the tables we want to
// convert into our widget.
// After we find them, we need to loop through them and take some
// actions on them
// At the conclusion of this block of code, each table that's going to
// be a percentSort widget will have been transformed
$("table.percentSort").each(function(i){
// each table needs a unique ID, for namespace issues (discussed later)
// we can simply create a uniqueID from the loop counter
$(this).attr("id", "percentSort-"+i);
// within each table, let's highlight every other row in the table, to
// give it that "zebra" look
$(this).find("tbody > tr").filter(":odd").addClass("highlight");
// because each table needs to show the "Total" to the user, let's create a new
// section of the table in the footer. We'll add a row in the table footer
// to display the words "Total" and a span for the updated count.
$("#"+$(this).attr("id") + " tfoot")
.append("<tr><td>Total</td><td>
<span></span> %</td></tr>");
// finally, let's add the CLASS of "percentTotal" to the span we just
// created above. We'll use this information later to display
// the updated totals
$("#"+$(this).attr("id") + " tfoot span").addClass("percentTotal");
});
// now the second step, after we've completed setting up the tables themselves
// is to set up the individual table rows.
// We can similarly sort through each of them, taking the appropriate actions
// on each of them in turn.
// Upon completion of this block of code, each row in each table will be
// transformed for our widget
$("table.percentSort tbody > tr").each(function(i){
// get the namespace (to be discussed in the next section)
var NAMESPACE = $(this).parents("table.percentSort").attr("id");
// attach a unique ID to this row. We can use the loop counter
// to ensure the ID is unique on the page (which is a must on every page)
$(this).attr("id", "row"+i);
// now, within this row of the table, we need to find the text input, because
// we need to attach a class to them. We utilize the namespace, and also
// find the :text within the table row, and then attach the correct class
$("#"+$(this).attr("id") + " :text").addClass("percent");
// Finally, we attach a unique ID to each of the text inputs, and we do this by
// making it a combination of the table name and the row name.
$("#"+$(this).attr("id") + " .percent").
attr("id", NAMESPACE + "-" + $(this).attr("id"));
});
// Finally, because we know we only want numerical inputs, we restrict the text entry
// to just numbers. We must do this now, because up until this point, the page
// contained no elements with the CLASS "percent"
$(".percent").numeric();

As
you can see from this example, you can really introduce a lot of functionality
into your HTML code in the jQuery code. The benefits to this type of design
should be obvious, and follow along the lines of separation of roles, reuse of
code, and so on. You'll see this type of design in widget plug-ins as well, as they
take your seemingly simple HTML markup and turn it into whatever widget the
plug-in is designed for. Essentially, that's what you're doing here as well,
writing a plug-in to turn a simple table into a sorting and summation table.

Remember: Set up as much of the code in the jQuery code itself,
and use as little HTML as you can.

Namespace

Perhaps one of the most
confusing aspects of working with this type of design, and with jQuery itself,
is to properly understand the namespace in which the code is working. That's
why this example is so good, because it presents this problem in a very
visible way. Writing jQuery code when you know every ID and class on the page can be very straightforward and easy. That's
what it was designed for after all. What happens when you aren't sure how many
classes are on the page, or they start to overlap themselves? In this example,
you can see this issue right away. There are two of the exact same widgets!
Everything is overlapped. It looks like what happens when you don't take namespace
issues into account; your widgets start to interfere with each other and they
end up not working properly at all.

Figure 4. Ignoring namespace
issues

This happens because you are ignoring which widget specifically should be
updated in your bad code, simply calling things like $(".percentTotal"). Because you have multiple tables on the same page,
there are going to be multiple instances of the percentTotal class on the
page. Yes, if you only had 1 of these tables on a page, you could take for
granted that this would exist only once. But as pages become more advanced,
and widgets become more reused, that assumption should be tossed out the
window. Some people may ask, "Why not just use an ID here instead?" That
wouldn't solve the issue: after all, what ID would you give it? You can't use
"percentTotal" because that would create ambiguity. You can't use
"percentTotal-1" because that doesn't really mean anything on the page. (The
numbers are just arbitrarily created by you, after all.) You could
attach some reference to the table it's contained in, something like
"percentTotal-percentSort1," which would be one solution, but this is overly
complicating things. jQuery has a super-sophisticated and very easy to use
selection syntax, making these types of hybrid naming schemes unnecessary. Why
recreate the wheel here? Let's use jQuery's selection engine to solve your
namespace issues for you.

At the core of the problem in this widget, and
in general, is determining which widget the action took place in. Ask
yourselves when you enter a number in one of the textfields, how does jQuery
know which textfield the text was entered in? You attached an event to the
class of "percent" in the code of course, and you can reference it with the
$(this) inside your code. That brings
us to the next question: How does jQuery know which widget this occurred in,
so you can update the appropriate percentTotal field? Ummm.....I guess it
doesn't, at least not easily. That's right. While your code is elegant, in
that you can
attach an event to every textfield with a class of "percent" on the page, it
is inelegant if you simply ignore the containing widget in which the event
occurred.

The reason this problem is termed a namespace problem is
because you are being ambiguous with the naming of the widgets, which can lead
to
problems. For the jQuery code to work properly, each name needs to be
clearly defined in its own space, hence the term namespace. You must write
code that avoids overlapping names, so that each widget can be self-contained.
You should be able to add multiple instances of the same widget on the same
page without any of the names overlapping. Essentially, each widget must
stand alone on a page.

There is no one right way to deal with this
namespace issue, so I'll present my solution, which you can use in your own
code, or you can read about the problem and create your own better solution.
The reason I like this code is because it is simple to use (only 1 line), and
gives you some control over your own namespace. Take a look in Listing
10.

Listing 10. Namespace solution

// our event is attached to EVERY input text field with a CLASS of "percent"
// this makes our code look good, but can lead to namespace issues
$("table.percentSort input.percent").keyup(function(){
// this simple line can establish a namespace for us, by getting the unique
// ID attached to our table (the table is considered the "container" for
// our widget. It could be anything, depending on your specific code.)
// We pass the CLASS of our widget to the parents() function, because
// that effectively encapsulates the widget
var NAMESPACE = "#" + $(this).parents("table.percentSort").attr("id");
// with the namespace established, we can use the jQuery selection
// syntax to use this namespace as our prefix for all of our remaining
// searches. Notice how the ambiguity is removed for our search
// by CLASS of "percent" and "percentTotal"
// This solves our namespace issues
var sum = $(NAMESPACE + " input.percent").sum();
var totalField = $(NAMESPACE + " .percentTotal");

So,
by simply adding one line of code, you can encapsulate the widget and prevent
it from overlapping functions (often incorrectly) with other instances of
the widget (or even other widgets that have the unfortunate consequence of
using the same names for IDs or classes). This type of coding is very common
in plug-in code. The well-written plug-ins will be written with namespace issues
in mind, while you'll find the poorly written ones will ignore them. As you
can see in this example, it's relatively straightforward to use it in your own
code, and it can lead to a great amount of time saved down the road if your
page becomes more complex. For this reason, I would recommend you start your
jQuery code with namespace issues in mind right away, and use this solution
for all of your own coding.

Remember: When starting your own jQuery
code, always start with the namespace solution included. You can use the
solution above, or create your own. This will allow your code to grow in
complexity without this ever becoming an issue.

What's new in 1.3

In this
last section of the article, I wanted to go through the new features that were
introduced in the 1.3 release of jQuery. The 1.3 release was a big release in
terms of performance, and for this reason alone, you should move up to this
release level in your own code. However, there were several small additions to
the core code that can help you improve your own code.

The first
addition to the 1.3 core was the live()/die() functions I discussed in this article. These
were probably the most important addition, as you can tell, because they earned
an entire section of the article. The other main addition to the 1.3 core is
the jQuery.Event class, which encapsulates the
events that occur on the page in an Object. This is extremely beneficial for
event-intense applications, because it offers a well contained object that
relays all the information you'll need concerning the event. Information such
as the type, the target, the X and Y coordinates, and even a timestamp. This
information may have been available before 1.3, but it was not as well
documented, and certainly not as well encapsulated. Finally, the last addition
to the 1.3 release will be transparent to you the developer, but it is still
noteworthy. In this release, there is no more browser sniffing, where there
are specific if statements for a browser or version. You can imagine the
spaghetti code when dealing with all of the browsers it must support. This
also added a certain decay to each jQuery version, because browsers are always
coming into and going out of use. Instead, they detect functionality in the
browser, while being browser type/version agnostic. This means as new browsers
are created, and old ones disappear, the jQuery version will never need to be
updated. Good for sites that don't want to upgrade their jQuery versions every
year and the testing that would require.

Conclusion

This brings to a close
this article offering you some tips on how to turn your good jQuery code into
great jQuery code. jQuery is so simple to use (and such an improvement of
stand-alone JavaScript), that it's quite easy to write good jQuery code. Most
developers can be up and running in a few minutes. However, there is a
distinction between writing good code and great code. Great jQuery code is
concerned with performance as the page complexity increases. Great jQuery code
thinks ahead to where a page is going, not where it is now, and codes for that
expectation. Great jQuery code is designed for the most complex application
possible, and then easily handles the simple stuff you throw at it.

This article introduced you to 5 concepts that can help your good
jQuery code become great jQuery code. The first concept was the use of the
bind()/unbind()
methods. These methods are quite useful in attaching/detaching events to your
page elements, when you don't want them attached to your code for the page's
life. This can be important in performance situations, where events can ripple
through the page, or it can be used in certain user interface situations. The
second concept was the usage of the new live()/die() features in 1.3. These
functions allow your events to be dynamic, just like your page elements. As
page elements get added in your Web appliction, these functions allow your
code to grow with your page, which wasn't possible before this release. You
want your event handling to be as dynamic as your page. The third addition was
the Ajax Queue/Sync plug-in, which should be used to regulate and control your
Ajax calls to the server in situations where they could grow out of control
(from a client perspective), and when the order in which they are returned is
important. The fourth recommendation was to write as much of the page setup
code in your jQuery code as possible. This allows your HTML to be simpler to
write, and gives you more power when setting up your page. Finally, the last
step was to utilize a namespace solution (either mine or your own) in your
code to prevent widgets from overlapping functions and causing errors on
your page. Each page element and widget should be self-contained and not
interfere with other aspects of the page, and this solution will prevent that.

These 5 tidbits are by no means difficult. In fact, for 4 of them,
it's as simple as changing one line of code. However, it's important to
understand how these solutions can be used in your code. Like everything else,
if they're used improperly they wouldn't help your code, and could actually hurt it. My
recommendation is to start using these 5 things as soon as you start coding
your jQuery on a page. Like every developer can tell you, feature creep is a
standard part of our lives. You do not want to have to redesign your entire
Web application because you made a poor decision at the beginning, or if
you're being forced to change something because your manager demands it. Start
your code with a great application in mind, and use these suggestions to get
you there.

Finally, this brings to a close this second cycle in my
jQuery series. These last 5 articles have brought you up to the next level in
your jQuery profiency, and by now you should be able to create any type of
application using the library. My final recommendation is to just play around
with the code for awhile and experiment. You'll not only learn a lot, you
may create the next cool thing on the Web!