home

Foundations of Programming 2 - Appendix A - jQuery Basics

Mar 16, 2011

Appendix A - jQuery Basics

There's a common anecdote given by web developers, it goes something like I hated JavaScript, then jQuery came along and now I love it. jQuery is a JavaScript library which takes the pain out of manipulating the DOM and creating reusable JavaScript code. It isn't the only framework of its kind, but it has established itself as the most popular. Part of what makes jQuery so powerful is that it focuses on a few specific things, allowing it to be very good at those. There are two parts to mastering jQuery: first the basics of the library, then how to use the basics to build your own plugins.

A huge part of knowing jQuery is knowing the jQuery method and jQuery object. The jQuery method is responsible for turning a normal HTML DOM element into a jQuery object. $ a shorthand for jQuery, the two are interchangeable, but most people prefer to use $ (I know, it seems magical, but it's just a function name - JavaScript allows such characters in function names). A jQuery object is a wrapper around a DOM element which provides all type of useful manipulation and traversing methods. Let's first look at the jQuery method, and then look at jQuery objects.

jQuery()

In its simplest form, the jQuery method will turn a DOM element into a jQuery element:

<div id="main"></div>
<script type="text/javascript">
    var domElement = document.getElementById('main');
    var $main = $(domElement);
    //or (same thing):
    var $main = jQuery(domElement);
</script>

(using $ as a prefix to jQuery object variables is a convention I like, if you don't, don't use it.)

Being able to turn a DOM element into a jQuery object is useful, as we'll see in a bit. However, the real power of the jQuery method (and jQuery in general) is its ability to take a CSS selector and turn that directly into a jQuery object wrapping the underlying DOM. This is nice for a couple reasons. First, you probably already know how CSS selectors work. Second, CSS selectors have proven to be quite flexible and powerful at selecting elements. Knowing this, we can drop the call to getElementById from the above example and simply do:

var $main = $('#main');

Because, in CSS, you target an element by id using the #ID selector. Also, jQuery takes care of cross browser incompatibilities for you. It doesn't matter that IE6 (or 7) doesn't support attribute selector such as input[type="text"]. The jQuery selector syntax is like CSS selectors, but it uses its own engine, independent of the browser's.

jQuery object

Before we dig too deeply into the jQuery method, let's get up to speed with what it returns: a jQuery object. Actually, the method always returns an array of jQuery objects - even when you know it should just return a single value, like in the above code when we selected by id. This actually turns out to provide some nice consistency, in addition to cleaner code (no null checking), as should become evident as we move forward. A jQuery object can be manipulated via various built-in jQuery methods, 3rd party plugins, or your own custom plugins. For now, we'll stick to the built-in methods. Let's look at some examples:

$main.text('welcome!');
$main.addClass('heading');
$main.click(function()
{
    alert('WELCOME!');
});

As a general rule, a jQuery method (built-in or not) returns the array of jQuery object being manipulated. This means that method calls are meant to be chained, so the above can be rewritten as:

$main.text('welcome').addClass('heading').click(function()
{
    alert('WELCOME!');
});

When dealing with an array of jQuery objects with more than 1 element, all elements items are affected. When dealing with an empty element, nothing happens.

The built-in jQuery method can be broken down into specific categories of behavior. Let's look at a few of the methods in each category.

Attribute Methods

Attribute methods let you manipulate the HTML attributes of the DOM elements your jQuery array wraps. We already saw the text and addClass methods above, but there's also the more generic attr and css methods, as well as a handful of others:

$links.attr('href', '#')
    .text('DOH!')
    .removeClass('active');

Some jQuery attribute methods have a fairly unique property: they don't return the original array of jQuery objects. Luckily, this is actually pretty intuitive. You see, most of them can be used for both setting a value (like we see above) or reading a value. When reading a value, logically, the value itself is returned (and it's only the first value of the array):

var firstLink = $('a').attr('href');
var tablesBorder = $('table.list').css('border');
var username = $('input[name="username"]).val();

Traversing

jQuery has an extensive number of traversal methods which let you get to jQuery objects starting from other jQuery objects. The simplest example is the children method:

<ul id="menu">
    <li><a href="#" class="current">home</a></li>
    <li><a href="#">login</a></li>
    <li><a href="#>register</a></li>
</ul>

<script type="text/javascript">
    var $menuItems = $('ul li');
    //or
    var $menuItems = $('ul').children();
</script>

The find method is similar to children except it looks at the children of children (all the way down). So, to find the current menu item, we could do any of the following:

var $current = $('.current'); //might return more than we want
var $current = $('#menu .current'); //just a normal css selector
var $current = $('#menu').find('.current');
var $current = $('#menu').children().children('.current');
var $current = $('#menu a').filter('.current');

Here we see both find and filter at play (as well as an overload of children which takes a selector). All of this is just the tip of the iceberg of both what's built in and what's possible. Here are two other, very common examples:

$current.sibling().addClass('notActive');
var $menu = $current.closest('ul');

sibling is self-explanatory. closest is the opposite of find going up the hierarchy looking for a match. There's also parent which finds the immediate parent, but if you find yourself chaining calls to parent it'll almost always be better to use closest:

var $menu = $current.closest('ul'); //much better than:
var $menu = $current.parent().parent();

It's possible that you are put off by the seemingly limitless way you can target specific elements. The truth is that in real code and with a experience, a best way is generally obvious.

Manipulation

The manipulation method give us great control over changing our elements. There's some overlap between these and the attribute methods, so we'll focus on moving things around:

$('#menu').clone().appendTo($('body'));
$('.current').remove();
$('#menu a).wrapAll('<p></p>');

These kind of methods are particularly useful when writing plugins and aren't as useful as standalone calls.

Events

Event methods let you cleanly hook up events (again, in a cross platform manner) to jQuery objects. For example, not all browsers support the CSS :hover pseudo-selector on all types of elements, but with jQuery we can use the mouseenter and mouseleave events to accomplish something similar (there's also a hover event, but I find it somewhat cumbersome):

$('tr').mouseenter(function()
{
    $(this).addClass('hover');
}).mouseleave(function()
{
    $(this).removeClass('hover');
}).click(function()
{
    alert('Your clicked the row at index: ' + $(this).index());
});

Woah, what's all $(this) about? this is the one tricky thing you'll have to really think about if you want to learn jQuery - it's where normal JavaScript bleeds into jQuery. this is a special keyword in JavaScript which has special contextual meaning - change the context, and chances are this will mean something else (when you think about it, this is true of C# as well). When JavaScript raises an event, this becomes the DOM element on which the event was raised. In our example above, this is the table row (tr) which caused either a mouse enter or mouse leave event. As we saw in our very first jQuery example, a DOM element can be turned into a jQuery element by using the jQuery method. So, in short, $(this) is turning the DOM element represented by this (which in the case of events is the DOM element which caused the event) into a jQuery object.

document.ready

There's one special event that we probably should have talked about by now. All of our jQuery examples have placed our JavaScript code directly in a