This guide is an introduction to the jQuery library. Knowledge of javascript and the document object model (DOM) is required. It starts from ground up and tries to explain details where necessary. It covers a simple hello world example, selector and event basics, AJAX, FX and usage and authoring of plugins.
This guide contains no "click me" examples. The intention of providing only "copy me" code is to invite you to try it for yourself. Copy an example, see what it does, and modify it.
Table of contents
Setup
To start, we need a copy of the jQuery library. While the most recent version can be found here, this guide provides a basic package you can download.
Download this file and extract it contents. Open starterkit.html and custom.js with your favorite editor and starterkit.html with a browser.
Now we have everything to start with the notorious "Hello world" example.
Interesting links for this chapter:
Hello jQuery
As almost everything we do when using jQuery reads or manipulates the document object model (DOM), we need to make sure that we start adding events etc. as soon as the DOM is ready.
To do this, we register a ready event for the document.
$(document).ready(function() { // do stuff when DOM is ready });
Putting an alert into that function does not make much sense, as an alert does not require the DOM to be loaded. So lets try something a little more sophisticated: Show an alert when clicking the link.
$(document).ready(function() { $("a").click(function() { alert("Hello world!"); }); });
This should show the alert as soon as you click on the link.
Lets have a look at what we are doing: $("a")
is a jQuery selector, in this case, it selects all a elements. $
itself is an alias for the jQuery "class", therefore $()
constructs a new jQuery object. The click()
function we call next is a method of the jQuery object. It binds a click event to all selected elements (in this case, a single anchor element) and executes the provided function when the event occurs.
This is similar to the following code:
<a href="#" οnclick="alert('Hello world')">Link</a>
The difference is quite obvious: We don't need to write an onclick for every single element. We have a clean seperation of structure (HTML) and behaviour (JS), just as we seperate structure and behaviour by using CSS.
With this in mind, we explore selectors and events a little further.
Interesting links for this chapter:
Find me: Using selectors and events
jQuery provides two approaches to select elements. The first uses a combination of CSS and XPath selectors passed as a string to the jQuery constructor (eg. $("div > ul a")
). The second uses several methods of the jQuery object. Both approaches can be combined.
To try some of these selectors, we select and modify the first ordered list in our starterkit.
To get started, we want to select the list itself. The list has an ID "orderedlist". In classic javascript, you could select it by using document.getElementById("orderedlist")
. With jQuery, we do it like this:
$(document).ready(function() { $("#orderedlist").addClass("red"); });
The starterkit provides a stylesheet with a class "red" that simply adds a red background. Therefore, when you reload the page in your browser, you should see that the first ordered list has a red background. The second list is not modified.
Now lets add some more classes to the child elements of this list.
$(document).ready(function() { $("#orderedlist > li").addClass("blue"); });
This selects all child li
s of the element with the id orderedlist and adds the class "blue".
Now for something a little more sophisticated: We want to add and remove the class when the user hovers the li element, but only on the last element in the list.
$(document).ready(function() { $("#orderedlist li:last").hover(function() { $(this).addClass("green"); }, function() { $(this).removeClass("green"); }); });
There a lots of other selectors similar to CSS and XPath syntax. More examples and a list of all available expressions can be found here.
For every onxxx event available, like onclick, onchange, onsubmit, there is an jQuery equivalent. Some other events, like ready and hover, are provided as convienent methods for certains tasks.
You can find a complete list of all events at Visual jQuery, filed under Events.
With those selectors and events you can already do alot of things, but there is more.
$(document).ready(function() { $("#orderedlist").find("li").each(function(i) { $(this).html( $(this).html() + " BAM! " + i ); }); });
find()
allows you to further search the descendants of the already selected elements, therefore $("#orderedlist).find("li")
is mostly the same as $("#orderedlist li")
. each()
iterates over every element and allows further processing. Most methods, like addClass()
, use each()
themselve. In this example, html()
is used to get the text of each li element, append some text to it and set it as text of the element.
Another task you often face is to call methods on DOM elements that are not covered by jQuery. Think of a form you like to reset after you submitted it successfully via AJAX.
$(document).ready(function() { // use this to reset a single form $("#reset").click(function() { $("#form")[0].reset(); }); });
This code selects the element with the ID "form" and calls reset()
on the first element selected. In case you had more than one form, you could also do this:
$(document).ready(function() { // use this to reset several forms at once $("#reset").click(function() { $("form").each(function() { this.reset(); }); }); });
This would select all forms within your document, iterate over them and call reset()
for each.
Another problem you might face is to not select certain elements. jQuery provides filter()
and not()
for this. While filter()
reduces the selection to the elements that fit the filter expression, not()
does the contrary and removes all elements that fit the expression. Think of an unordered list where you want to select all li elements, that have no ul child themselve.
$(document).ready(function() { $("li").not("[ul]").css("border", "1px solid black"); });
This selects all li elements and removes all elements from the selection, that have an ul element as a child. Therefore all li elements get a border, except the one that has a child ul. The [expression]
syntax is taken from XPath and can be used to filter by child elements and attributes. Maybe you want to select all anchors that have a name attribute:
$(document).ready(function() { $("a[@name]").background("#eee"); });
This adds a background color to all anchor elements with a name attribute.
More often then selecting anchors by name, you might need to selected anchors by their "href" attribute. This can be a problem as browsers behave quite inconsistently when returning what they think the "href" value is. To match only a part of the value, we can use the contains select "*=" instead of an equals ("="):
$(document).ready(function() { $("a[@href*=/content/gallery]").click(function() { // do something with all links that point somewhere to /content/gallery }); });
Until now, all selectors were used to select childs or filter the current selection. There are situations where you need to select the previous or next elements, known as siblings. Think of a FAQ page, where all answers are hidden first, and shown, when the question is clicked. The jQuery code for this:
$(document).ready(function() { $('#faq').find('dd').hide().end().find('dt').click(function() { var answer = $(this).next(); if (answer.is(':visible')) { answer.slideUp(); } else { answer.slideDown(); } }); });
Here we use some chaining to reduce the code size and gain better performance, as '#faq' is only selected once. By using end()
, the first find()
is undone, so we can start search with the next find()
at our #faq element, instead of the dd children.
Within the click handler, the function passed to the click()
method, we use $(this).next() to find the next sibling starting from the current dt. This allows us to quickly select the answer following the clicked question.
In addition to siblings, you can also select parent elements (also known as ancestors for those more familiar with XPath). Maybe you want to highlight the paragraph that is the parent of the link the user hovers. Try this:
$(document).ready(function() { $("a").hover(function() { $(this).parents("p").addClass("highlight"); }, function() { $(this).parents("p").removeClass("highlight"); }); });
For all hovered anchor elements, the parent paragraph is searched and a class "highlight" added and removed.
Lets go one step back before continuing: jQuery is alot about making code shorter and therefore easier to read and maintain. The following is a shortcut for the $(document).ready(callback) notation:
$(function() { // code to execute when the DOM is ready });
Applied to the Hello world! example, we end with this:
$(function() { $("a").click(function() { alert("Hello world!"); }); });
Now, with the basics at hand, we want to explore some other aspects, starting with AJAX.
Interesting links for this chapter:
Rate me: Using AJAX
In this part we write a small AJAX application, that allows the user to rate something, just like it is done on youtube.com.
We need some server code for this. My example uses a php file that reads the "rating" parameter and returns the number of ratings and the average rating. Have a look at rate.php for the server-side code.
We don't want this example to work without AJAX, although it may be possible, we therefore generate the necessary markup with jQuery and append it to a container div with an ID of "rating".
$(document).ready(function() { // generate markup var ratingMarkup = ["Please rate: "]; for(var i=1; i <= 5; i++) { ratingMarkup[ratingMarkup.length] = "<a href='#'>" + i + "</a> "; } // add markup to container and applier click handlers to anchors $("#rating").append( ratingMarkup.join('') ).find("a").click(function(e) { e.preventDefault(); // send requests $.post("rate.php", {rating: $(this).html()}, function(xml) { // format result var result = [ "Thanks for rating, current average: ", $("average", xml).text(), ", number of votes: ", $("count", xml).text() ]; // output result $("#rating").html(result.join('')); } ); }); });
This snippet generates five anchor elements and appends them to the container element with the id "rating". Afterwards, for every anchor inside the container, a click handler is added. When the anchor is clicked, a post request is send to rate.php with the content of the anchor as a parameter. The result returned as a XML is then added to the container, replacing the anchors.
If you don't have a webserver with PHP installed at hand, you can look at an online example.
For a very nice example of a rating system that even works without javascript, visit softonic.de and click on "Kurz bewerten!"
More documentation of the AJAX methods of jQuery can be found here or on Visual jQuery filed under AJAX.
A very common problem encountered when loading content by AJAX is this: When adding event handlers to your document that should also apply to the loaded content, you have to apply these handlers after the content is loaded. To prevent code duplication, you can delegate to a function. Example:
// lets use the shortcut $(function() { var addClickHandlers = function() { $("a.clickMeToLoadContent").click(function() { $("#target").load(this.href, addClickHandlers); }); }; addClickHandlers(); });
Now addClickHandlers is applied once when the DOM is ready and then everytime when a user clicked a link with the class clickMeToLoadContent
and the content has finished loading.
Please note that the function "addClickHandlers" is defined as a local variable, instead of a global function (like function addClickHandlers() {...}
). Stick to this to prevent conflicts with other global variables or functions.
Another common problem with callbacks are parameters. You have specified your callback but need to pass an extra paramter. The easiert way to achieve this is to wrap the callback inside another function:
// get some data var foobar = ...; // specify handler, it needs data as a paramter var handler = function(data) { ... }; // add click handler and pass foobar! $('a').click( function(event) { handler(foobar); } ); // if you need the context of the original handler, use apply: $('a').click( function(event) { handler.apply(this, [foobar]); } );
With AJAX this simple we can cover quite a lot "Web 2.0". But until now, we lack fancy effects.
Interesting links for this chapter:
Animate me: Using FX
Simple animations with jQuery can be achieved with show()
and hide()
$(document).ready(function() { $("a").toggle(function() { $(".stuff").hide('slow'); }, function() { $(".stuff").show('fast'); }); });
You can create any combination of animations with animate()
, eg. a slide with a fade:
$(document).ready(function() { $("a").toggle(function() { $(".stuff").animate({ height: 'hide', opacity: 'hide' }, 'slow'); }, function() { $(".stuff").animate({ height: 'show', opacity: 'show' }, 'slow'); }); });
Much fancier effects can be achieved with the interface plugin collection. The site provides demos and documentation
While Interface is at the top of jQuerys plugin list, there are lots of others. The next part shows how to use the tablesorter plugin.
Interesting links for this chapter:
Sort me: Using the tablesorter plugin
The tablesorter plugin allows sorting of tables on the client side. You include jQuery and the plugin and tell the plugin which tables you want to sort.
To try this example, add this line to starterkit.html (below the jquery include):
<script src="lib/jquery.tablesorter.js" type="text/javascript"></script>
After including the plugin, you can call it like this:
$(document).ready(function() { $("#large").tableSorter(); });
Try clicking the headers of the table and see how it is sorted ascending on first click and descending on second.
The table could use some row highlighting, we can add those by passing some options:
$(document).ready(function() { $("#large").tableSorter({ stripingRowClass: ['odd','even'], // Class names for striping supplyed as a array. stripRowsOnStartUp: true // Strip rows on tableSorter init. }); });
There are more examples and documentation about the available options at the tablesorter hompage.
Most plugins can be used like this: Include the plugin file and call the plugin method on some elements, passing some optional settings to customize the plugin.
A up-to-date list of available plugins can be found on the jQuery site.
When you are using jQury more often, you may find it useful to package your own code as a plugin, either to reuse it for yourself or your company, or to share it with the community. The next chapter gives some hints on how to structure a plugin.
Interesting links for this chapter:
Plug me: Writing your own plugins
Writing your own plugins for jQuery is quite easy. If you stick to the following rules, it is easy for others to integrate your plugin, too.
- Find a name for your plugin, lets call our example "foobar".
- Create a file named jquery.[yourpluginname].js, eg. jquery.foobar.js
- Create one or more plugin methods by extending the jQuery object, eg.:
jQuery.fn.foobar = function() { // do something };
- Optional: Create an object with helper functions, eg.:
jQuery.fooBar = { height: 5, calculateBar = function() { ... }, checkDependencies = function() { ... } };
You can then call these helper function from within your plugin:
jQuery.fn.foobar = function() { // do something jQuery.foobar.checkDependencies(value); // do something else };
- Optional: Create default settings that can be changed by the user, eg.:
jQuery.fn.foobar = function(options) { var settings = { value: 5, name: "pete", bar: 655 }; if(options) { jQuery.extend(settings, options); } };
You can then call the plugin without options, using the defaults:
$("...").foobar();
Or with some options:
$("...").foobar({ value: 123, bar: 9 });
If you release your plugin, you should provide some examples and documentation, too. There are lots of plugins available as a great reference.
Now you should have the basic idea of plugin writing. Lets use this knowledge and write our own plugin.
Something lots of people, trying to manipulate forms with jQuery, ask for, is checking and unchecking of radio buttons or checkboxes. They end up with code like this:
$("input[@type='checkbox']").each(function() { this.checked = true; // or, to uncheck this.checked = false; // or, to toggle this.checked = !this.checked; });
Whenever you have an each in your code, you might want to rewrite that as a plugin, pretty straightforward:
$.fn.check = function() { return this.each(function() { this.checked = true; }); };
This plugin can now be used:
$("input[@type='checkbox']").check();
Now you could write plugins for both uncheck() and toggleCheck(), too. But instead we extend our plugin to accept some options.
$.fn.check = function(mode) { var mode = mode || 'on'; // if mode is undefined, use 'on' as default return this.each(function() { switch(mode) { case 'on': this.checked = true; break; case 'off': this.checked = false; break; case 'toggle': this.checked = !this.checked; break; } }); };
By providing a default for the option, the user can omit the option or pass one of "on", "off", and "toggle", eg.:
$("input[@type='checkbox']").check(); $("input[@type='checkbox']").check('on'); $("input[@type='checkbox']").check('off'); $("input[@type='checkbox']").check('toggle');
With more than one optional setting, this approach gets complicated, because the user must pass null values if he wants to omit the first parameter and only use the second.
The use of the tablesorter in the last chapter demonstrates the use of an object literal to solve this problem. The user can omit all paramters or pass an object with a key/value pair for every setting he wants to override.
For an exercise, you could try to rewrite the code from the fourth chapter as a plugin. The plugin skeleton should look like this:
$.fn.rateMe = function(options) { var container = this; // instead of selecting a static container with $("#rating"), we now use the jQuery context var settings = { url: "rate.php" // put more defaults here // remember to put a comma (",") after each pair, but not after the last one! }; if(options) { // check if options are present before extending the settings $.extend(settings, options); } // ... // rest of the code // ... return this; // if possible, return "this" to not break the chain });
Next steps
If you plan to develop more javascript, you should consider the Firefox extension called FireBug. It provides a console (nice to replace alerts), a debugger and other useful stuff for the daily javascript development.
If you have problems you can't solve, ideas you want to share or just the need to express your opinion on jQuery, feel free to post to the jQuery mailing list.
For anything related to this guide, send me a mail or post a comment on my blog.
Whats left...
Thanks a lot to John Resig for this great library! Thanks to the jQuery community for providing John with enough coffee and everything else!