Commonly Confused Bits Of jQuery

Advertisement

The explosion of JavaScript libraries and frameworks such as jQuery onto the front-end development scene has opened up the power of JavaScript to a far wider audience than ever before. It was born of the need — expressed by a crescendo of screaming by front-end developers who were fast running out of hair to pull out — to improve JavaScript’s somewhat primitive API, to make up for the lack of unified implementation across browsers and to make it more compact in its syntax.

All of which means that, unless you have some odd grudge against jQuery, those days are gone — you can actually get stuff done now. A script to find all links of a certain CSS class in a document and bind an event to them now requires one line of code, not 10. To power this, jQuery brings to the party its own API, featuring a host of functions, methods and syntactical peculiarities. Some are confused or appear similar to each other but actually differ in some way. This article clears up some of these confusions.

1. .parent() vs. .parents() vs. .closest()

All three of these methods are concerned with navigating upwards through the DOM, above the element(s) returned by the selector, and matching certain parents or, beyond them, ancestors. But they differ from each other in ways that make them each uniquely useful.

parent(selector)

This simply matches the one immediate parent of the element(s). It can take a selector, which can be useful for matching the parent only in certain situations. For example:

$('span#mySpan').parent().css('background', '#f90');
$('p').parent('div.large').css('background', '#f90');

The first line gives the parent of #mySpan. The second does the same for parents of all <p> tags, provided that the parent is a div and has the class large.

Tip: the ability to limit the reach of methods like the one in the second line is a common feature of jQuery. The majority of DOM manipulation methods allow you to specify a selector in this way, so it’s not unique to parent().

parents(selector)

This acts in much the same way as parent(), except that it is not restricted to just one level above the matched element(s). That is, it can return multiple ancestors. So, for example:

$('li.nav').parents('li'); //for each LI that has the class nav, go find all its parents/ancestors that are also LIs

This says that for each <li> that has the class nav, return all its parents/ancestors that are also <li>s. This could be useful in a multi-level navigation tree, like the following:

<ul id='nav'>
	<li>Link 1
		<ul>
			<li>Sub link 1.1</li>
			<li>Sub link 1.2</li>
			<li>Sub link 1.3</li>
		</ul>
	<li>Link 2
		<ul>
			<li>Sub link 2.1

			<li>Sub link 2.2

		</ul>
	</li>
</ul>

Imagine we wanted to color every third-generation <li> in that tree orange. Simple:

$('#nav li').each(function() {
	if ($(this).parents('#nav li').length == 2)
		$(this).css('color', '#f90');
});

This translates like so: for every <li> found in #nav (hence our each() loop), whether it’s a direct child or not, see how many <li> parents/ancestors are above it within #nav. If the number is two, then this <li> must be on level three, in which case color.

closest(selector)

This is a bit of a well-kept secret, but very useful. It works like parents(), except that it returns only one parent/ancestor. In my experience, you’ll normally want to check for the existence of one particular element in an element’s ancestry, not a whole bunch of them, so I tend to use this more than parents(). Say we wanted to know whether an element was a descendant of another, however deep in the family tree:

if ($('#element1').closest('#element2').length == 1)
	alert("yes - #element1 is a descendent of #element2!");
else
	alert("No - #element1 is not a descendent of #element2");

Tip: you can simulate closest() by using parents() and limiting it to one returned element.

$($('#element1').parents('#element2').get(0)).css('background', '#f90');

One quirk about closest() is that traversal starts from the element(s) matched by the selector, not from its parent. This means that if the selector that passed inside closest() matches the element(s) it is running on, it will return itself. For example:

$('div#div2').closest('div').css('background', '#f90');

This will turn #div2 itself orange, because closest() is looking for a <div>, and the nearest <div> to #div2 is itself.

2. .position() vs. .offset()

These two are both concerned with reading the position of an element — namely the first element returned by the selector. They both return an object containing two properties, left and top, but they differ in what the returned position is relative to.

position() calculates positioning relative to the offset parent — or, in more understandable terms, the nearest parent or ancestor of this element that has position: relative. If no such parent or ancestor is found, the position is calculated relative to the document (i.e. the top-left corner of the viewport).

offset(), in contrast, always calculates positioning relative to the document, regardless of the position attribute of the element’s parents and ancestors.

Consider the following two <div>s:

Hello – I’m outerDiv. I have position: relative and left: 100px

Hi – I’m #innerDiv. I have position absolute, left: 50px and top: 80px.

Querying (no pun intended) the offset() and position() of #innerDiv will return different results.

var position = $('#innerDiv').position();
var offset = $('#innerDiv').offset();
alert("Position: left = "+position.left+", top = "+position.top+"n"+
      "Offset: left = "+offset.left+" and top = "+offset.top
)

Try it yourself to see the results: click here1.

3. .css(‘width’) and .css(‘height’) vs. .width() and .height()

These three, you won’t be shocked to learn, are concerned with calculating the dimensions of an element in pixels. They both return the offset dimensions, which are the genuine dimensions of the element no matter how stretched it is by its inner content.

They differ in the data types they return: css('width') and css('height') return dimensions as strings, with px appended to the end, while width() and height() return dimensions as integers.

There’s actually another little-known difference that concerns IE (quelle surprise!), and it’s why you should avoid the css('width') and css('height') route. It has to do with the fact that IE, when asked to read “computed” (i.e. not implicitly set) dimensions, unhelpfully returns auto. In jQuery core, width() and height() are based on the .offsetWidth and .offsetHeight properties resident in every element, which IE does read correctly.

But if you’re working on elements with dimensions implicitly set, you don’t need to worry about that. So, if you wanted to read the width of one element and set it on another element, you’d opt for css('width'), because the value returned comes ready appended with ‘px’.

But if you wanted to read an element’s width() with a view to performing a calculation on it, you’d be interested only in the figure; hence width() is better.

Note that each of these can simulate the other with the help of an extra line of JavaScript, like so:

var width = $('#someElement').width(); //returns integer
width = width+'px'; //now it's a string like css('width') returns
var width = $('#someElement').css('width'); //returns string
width = parseInt(width); //now it's an integer like width() returns

Lastly, width() and height() actually have another trick up their sleeves: they can return the dimensions of the window and document. If you try this using the css() method, you’ll get an error.

4. .click() (etc) vs. .bind() vs. .live() vs. .delegate

These are all concerned with binding events to elements. The differences lie in what elements they bind to and how much we can influence the event handler (or “callback”). If this sounds confusing, don’t worry. I’ll explain.

click() (etc)

It’s important to understand that bind() is the daddy of jQuery’s event-handling API. Most tutorials deal with events with simple-looking methods, such as click() and mouseover(), but behind the scenes these are just the lieutenants who report back to bind().

These lieutenants, or aliases, give you quick access to bind certain event types to the elements returned by the selector. They all take one argument: a callback function to be executed when the event fires. For example:

$('#table td ').click(function() {
	alert("The TD you clicked contains '"+$(this).text()+"'");
});

This simply says that whenever a <div> inside #table is clicked, alert its text content.

bind()

We can do the same thing with bind, like so:

$('#table td ').bind('click', function() {
	alert("The TD you clicked contains '"+$(this).text()+"'");
});

Note that this time, the event type is passed as the first argument to bind(), with the callback as the second argument. Why would you use bind() over the simpler alias functions?

Very often you wouldn’t. But bind() gives you more control over what happens in the event handler. It also allows you to bind more than one event at a time, by space-separating them as the first argument, like so:

$('#table td').bind('click contextmenu', function() {
	alert("The TD you clicked contains '"+$(this).text()+"'");
});

Now our event fires whether we’ve clicked the <td> with the left or right button. I also mentioned that bind() gives you more control over the event handler. How does that work? It does it by passing three arguments rather than two, with argument two being a data object containing properties readable to the callback, like so:

$('#table td').bind('click contextmenu', {message: 'hello!'}, function(e) {
	alert(e.data.message);
});

As you can see, we’re passing into our callback a set of variables for it to have access to, in our case the variable message.

You might wonder why we would do this. Why not just specify any variables we want outside the callback and have our callback read those? The answer has to do with scope and closures. When asked to read a variable, JavaScript starts in the immediate scope and works outwards (this is a fundamentally different behavior to languages such as PHP). Consider the following:

var message = 'you left clicked a TD';
$('#table td').bind('click', function(e) {
	alert(message);
});
var message = 'you right clicked a TD';
$('#table td').bind('contextmenu', function(e) {
	alert(message);
});

No matter whether we click the <td> with the left or right mouse button, we will be told it was the right one. This is because the variable message is read by the alert() at the time of the event firing, not at the time the event was bound.

If we give each event its own “version” of message at the time of binding the events, we solve this problem.

$('#table td').bind('click', {message: 'You left clicked a TD'}, function(e) {
	alert(e.data.message);
});
$('#table td').bind('contextmenu', {message: 'You right clicked a TD'}, function(e) {
	alert(e.data.message);
});

Events bound with bind() and with the alias methods (.mouseover(), etc) are unbound with the unbind() method.

live()

This works almost exactly the same as bind() but with one crucial difference: events are bound both to current and future elements — that is, any elements that do not currently exist but which may be DOM-scripted after the document is loaded.

Side note: DOM-scripting entails creating and manipulating elements in JavaScript. Ever notice in your Facebook profile that when you “add another employer” a field magically appears? That’s DOM-scripting, and while I won’t get into it here, it looks broadly like this:

var newDiv = document.createElement('div');
newDiv.appendChild(document.createTextNode('hello, world!'));
$(newDiv).css({width: 100, height: 100, background: '#f90'});
document.body.appendChild(newDiv);

delegate()

A shortfall of live() is that, unlike the vast majority of jQuery methods, it cannot be used in chaining. That is, it must be used directly on a selector, like so:

$('#myDiv a').live('mouseover', function() {
	alert('hello');
});

But not…

$('#myDiv').children('a').live('mouseover', function() {
	alert('hello');
});

… which will fail, as it will if you pass direct DOM elements, such as $(document.body).

delegate(), which was developed as part of jQuery 1.4.2, goes some way to solving this problem by accepting as its first argument a context within the selector. For example:

$('#myDiv').delegate('a', 'mouseover', function() {
	alert('hello');
});

Like live(), delegate() binds events both to current and future elements. Handlers are unbound via the undelegate() method.

Real-Life Example

For a real-life example, I want to stick with DOM-scripting, because this is an important part of any RIA (rich Internet application) built in JavaScript.

Let’s imagine a flight-booking application. The user is asked to supply the names of all passengers travelling. Entered passengers appear as new rows in a table, #passengersTable, with two columns: “Name” (containing a text field for the passenger) and “Delete” (containing a button to remove the passenger’s row).

To add a new passenger (i.e. row), the user clicks a button, #addPassenger:

$('#addPassenger').click(function() {
	var tr = document.createElement('tr');
	var td1 = document.createElement('td');
	var input = document.createElement('input');
	input.type = 'text';
	$(td1).append(input);
	var td2 = document.createElement('td');
	var button = document.createElement('button');
	button.type = 'button';
	$(button).text('delete');
	$(td2).append(button);
	$(tr).append(td1);
	$(tr).append(td2);
	$('#passengersTable tbody').append(tr);
});

Notice that the event is applied to #addPassenger with click(), not live('click'), because we know this button will exist from the beginning.

What about the event code for the “Delete” buttons to delete a passenger?

$('#passengersTable td button').live('click', function() {
	if (confirm("Are you sure you want to delete this passenger?"))
	$(this).closest('tr').remove();
});

Here, we apply the event with live() because the element to which it is being bound (i.e. the button) did not exist at runtime; it was DOM-scripted later in the code to add a passenger.

Handlers bound with live() are unbound with the die() method.

The convenience of live() comes at a price: one of its drawbacks is that you cannot pass an object of multiple event handlers to it. Only one handler.

5. .children() vs. .find()

Remember how the differences between parent(), parents() and closest() really boiled down to a question of reach? So it is here.

children()

This returns the immediate children of an element or elements returned by a selector. As with most jQuery DOM-traversal methods, it is optionally filtered with a selector. So, if we wanted to turn all <td>s orange in a table that contained the word “dog”, we could use this:

$('#table tr').children('td:contains(dog)').css('background', '#f90');

find()

This works very similar to children(), only it looks at both children and more distant descendants. It is also often a safer bet than children().

Say it’s your last day on a project. You need to write some code to hide all <tr>s that have the class hideMe. But some developers omit <tbody> from their table mark-up, so we need to cover all bases for the future. It would be risky to target the <tr>s like this…

$('#table tbody tr.hideMe').hide();

… because that would fail if there’s no <tbody>. Instead, we use find():

$('#table').find('tr.hideMe').hide();

This says that wherever you find a <tr> in #table with .hideMe, of whatever descendancy, hide it.

6. .not() vs. !.is() vs. :not()

As you’d expect from functions named “not” and “is,” these are opposites. But there’s more to it than that, and these two are not really equivalents.

.not()

not() returns elements that do not match its selector. For example:

$('p').not('.someclass').css('color', '#f90');

That turns all paragraphs that do not have the class someclass orange.

.is()

If, on the other hand, you want to target paragraphs that do have the class someclass, you could be forgiven for thinking that this would do it:

$('p').is('.someclass').css('color', '#f90');

In fact, this would cause an error, because is() does not return elements: it returns a boolean. It’s a testing function to see whether any of the chain elements match the selector.

So when is is useful? Well, it’s useful for querying elements about their properties. See the real-life example below.

:not()

:not() is the pseudo-selector equivalent of the method .not() It performs the same job; the only difference, as with all pseudo-selectors, is that you can use it in the middle of a selector string, and jQuery’s string parser will pick it up and act on it. The following example is equivalent to our .not() example above:

$('p:not(.someclass)').css('color', '#f90');

Real-Life Example

As we’ve seen, .is() is used to test, not filter, elements. Imagine we had the following sign-up form. Required fields have the class required.

<form id='myform' method='post' action='somewhere.htm'>
	<label>Forename *
	<input type='text' class='required' />
	<br />
	<label>Surname *
	<input type='text' class='required' />
	<br />
	<label>Phone number
	<input type='text' />
	<br />
	<label>Desired username *
	<input type='text' class='required' />
	<br />
	<input type='submit' value='GO' />
</form>

When submitted, our script should check that no required fields were left blank. If they were, the user should be notified and the submission halted.

$('#myform').submit(function() {
	if ($(this).find('input').is('.required[value=]')) {
		alert('Required fields were left blank! Please correct.');
		return false; //cancel submit event
	}
});

Here we’re not interested in returning elements to manipulate them, but rather just in querying their existence. Our is() part of the chain merely checks for the existence of fields within #myform that match its selector. It returns true if it finds any, which means required fields were left blank.

7. .filter() vs. .each()

These two are concerned with iteratively visiting each element returned by a selector and doing something to it.

.each()

each() loops over the elements, but it can be used in two ways. The first and most common involves passing a callback function as its only argument, which is also used to act on each element in succession. For example:

$('p').each(function() {
	alert($(this).text());
});

This visits every <p> in our document and alerts out its contents.

But each() is more than just a method for running on selectors: it can also be used to handle arrays and array-like objects. If you know PHP, think foreach(). It can do this either as a method or as a core function of jQuery. For example…

var myarray = ['one', 'two'];
$.each(myarray, function(key, val) {
	alert('The value at key '+key+' is '+val);
});

… is the same as:

var myarray = ['one', 'two'];
$(myarray).each(function(key, val) {
	alert('The value at key '+key+' is '+val);
});

That is, for each element in myarray, in our callback function its key and value will be available to read via the key and val variables, respectively. The first of the two examples is the better choice, since it makes little sense to pass an array as a jQuery selector, even if it works.

One of the great things about this is that you can also iterate over objects — but only in the first way (i.e. $.each).

jQuery is known as a DOM-manipulation and effects framework, quite different in focus from other frameworks such as MooTools, but each() is an example of its occasional foray into extending JavaScript’s native API.

.filter()

filter(), like each(), visits each element in the chain, but this time to remove it from the chain if it doesn’t pass a certain test.

The most common application of filter() is to pass it a selector string, just like you would specify at the start of a chain. So, the following are equivalents:

$('p.someClass').css('color', '#f90');
$('p').filter('.someclass').css('color', '#f90');

In which case, why would you use the second example? The answer is, sometimes you want to affect element sets that you cannot (or don’t want to) change. For example:

var elements = $('#someElement div ul li a');
//hundreds of lines later...
elements.filter('.someclass').css('color', '#f90');

elements was set long ago, so we cannot — indeed may not wish to — change the elements that return, but we might later want to filter them.

filter() really comes into its own, though, when you pass it a filter function to which each element in the chain in turn is passed. Whether the function returns true or false determines whether the element stays in the chain. For example:

$('p').filter(function() {
	return $(this).text().indexOf('hello') != -1;
}).css('color', '#f90')

Here, for each <p> found in the document, if it contains the string hello, turn it orange. Otherwise, don’t affect it.

We saw above how is(), despite its name, was not the equivalent of not(), as you might expect. Rather, use filter() or has() as the positive equivalent of not().

Note also that unlike each(), filter() cannot be used on arrays and objects.

Real-Life Example

You might be looking at the example above, where we turned <p>s starting with hello orange, and thinking, “But we could do that more simply.” You’d be right:

$('p:contains(hello)').css('color', '#f90')

For such a simple condition (i.e. contains hello), that’s fine. But filter() is all about letting us perform more complex or long-winded evaluations before deciding whether an element can stay in our chain.

Imagine we had a table of CD products with four columns: artist, title, genre and price. Using some controls at the top of the page, the user stipulates that they do not want to see products for which the genre is “Country” or the price is above $10. These are two filter conditions, so we need a filter function:

$('#productsTable tbody tr').filter(function() {
	var genre = $(this).children('td:nth-child(3)').text();
	var price = $(this).children('td:last').text().replace(/[^d.]+/g, '');
	return genre.toLowerCase() == 'country' || parseInt(price) >= 10;
}).hide();

So, for each <tr> inside the table, we evaluate columns 3 and 4 (genre and price), respectively. We know the table has four columns, so we can target column 4 with the :last pseudo-selector. For each product looked at, we assign the genre and price to their own variables, just to keep things tidy.

For the price, we replace any characters that might prevent us from using the value for mathematical calculation. If the column contained the value $14.99 and we tried to compute that by seeing whether it matched our condition of being below $10, we would be told that it’s not a number, because it contains the $ sign. Hence we strip away everything that is not number or dot.

Lastly, we return true (meaning the row will be hidden) if either of our conditions are met (i.e. the genre is country or the price is $10 or more).

filter()

8. .merge() vs. .extend()

Let’s finish with a foray into more advanced JavaScript and jQuery. We’ve looked at positioning, DOM manipulation and other common issues, but jQuery also provides some utilities for dealing with the native parts of JavaScript. This is not its main focus, mind you; libraries such as MooTools exist for this purpose.

.merge()

merge() allows you to merge the contents of two arrays into the first array. This entails permanent change for the first array. It does not make a new array; values from the second array are appended to the first:

var arr1 = ['one', 'two'];
var arr2 = ['three', 'four'];
$.merge(arr1, arr2);

After this code runs, the arr1 will contain four elements, namely one, two, three, four. arr2 is unchanged. (If you’re familiar with PHP, this function is equivalent to array_merge().)

.extend()

extend() does a similar thing, but for objects:

var obj1 = {one: 'un', two: 'deux'}
var obj2 = {three: 'trois', four: 'quatre'}
$.extend(obj1, obj2);

extend() has a little more power to it. For one thing, you can merge more than two objects — you can pass as many as you like. For another, it can merge recursively. That is, if properties of objects are themselves objects, you can ensure that they are merged, too. To do this, pass true as the first argument:

var obj1 = {one: 'un', two: 'deux'}
var obj2 = {three: 'trois', four: 'quatre', some_others: {five: 'cinq', six: 'six', seven: 'sept'}}
$.extend(true, obj1, obj2);

Covering everything about the behaviour of JavaScript objects (and how merge interacts with them) is beyond the scope of this article, but you can read more here2.

The difference between merge() and extend() in jQuery is not the same as it is in MooTools. One is used to amend an existing object, the other creates a new copy.

There You Have It

We’ve seen some similarities, but more often than not intricate (and occasionally major) differences. jQuery is not a language, but it deserves to be learned as one, and by learning it you will make better decisions about what methods to use in what situation.

It should also be said that this article does not aim to be an exhaustive guide to all jQuery functions available for every situation. For DOM traversal, for example, there’s also nextUntil() and parentsUntil().

While there are strict rules these days for writing semantic and SEO-compliant mark-up, JavaScript is still very much the playground of the developer. No one will demand that you use click() instead of bind(), but that’s not to say one isn’t a better choice than the other. It’s all about the situation.

Related Posts

You may be interested in the following related posts:

We appreciate the feedback of our Twitter followers who reviewed the article before it was published.

(al)

Footnotes

  1. 1 javascript:getPositionAndOffset()
  2. 2 http://api.jquery.com/jQuery.extend/
  3. 3 http://www.smashingmagazine.com/2010/04/20/seven-javascript-things-i-wish-i-knew-much-earlier-in-my-career/
  4. 4 http://www.smashingmagazine.com/2010/02/22/the-seven-deadly-sins-of-javascript-implementation/
  5. 5 http://www.smashingmagazine.com/2010/02/10/some-things-you-should-know-about-ajax/

↑ Back to topShare on Twitter

Andy Croxall is a Web developer from Wandsworth, London, England. He is a Javascript specialist and is an active member of the jQuery community, posting plugins and extensions. He has worked for clients ranging from the London Stock Exchange to Durex. You can keep up with him and his projects and creations on his website, mitya.co.uk.

Advertising
  1. 1

    Nice article, I did not even know about merge

    0
  2. 2

    Awesome article!

    0
  3. 3

    How can you not know what “DOM scripting” (never heard the two words together before – sounds a little strange) is and be allowed to use JavaScript?

    0
  4. 4

    Vipul Limbachiya

    August 4, 2010 6:28 am

    This is the best article.. I by self wanted clarification on all the points covered in this article. Thanks for sharing

    0
  5. 5

    Just a tiny comment: one should write ‘vs’ and not ‘vs.’, as ‘vs’ contains the first and the last letter of that word. The same goes with, for example, ‘Mr’ or ‘Dr’. Great article anyway.

    -1
  6. 6

    I didn’t know about .closest() but it makes a lot of sense, thanks!!

    1
  7. 7

    Nice article. parents() is pretty poorly named – it took me a while to remember that it’s not just parents, but ancestors as well. I guess the fact that an element can only have a single parent should make this more obvious, but the name just seems really counter-intuitive to me.

    Admittedly, I would rather type “parents” than “ancestors”, but this is still a nasty one for beginners.

    0
  8. 8

    First thing I thought as well :)
    Apart from that, nice article.
    For those new to Dom scripting, check out http://domscripting.com/book/ it’s the definitive introduction.

    1
  9. 9

    closest() is one of my favorite selectors.

    0
  10. 10

    Great article. I wasn’t familiar with “live” or using “parents” to target a specific parent. Life just got easier!

    1
  11. 11

    Magnificent work, Andy. You nailed all of them.

    Bobby, yeah the naming of `parents()` vs `children()` makes that point especially salient.

    $.inArray, $.fn.index, and $.fn.fadeTo are probably three more methods that have surprising APIs. Fine once you get used to do it, but less intuitive than most of the others.

    0
  12. 12

    Chris Schneider

    August 4, 2010 6:43 am

    great article, I was having some issues on a site of mine regarding the children ‘bit’ and I believe this will help me solve it! Thanks again!

    0
  13. 13

    A very nice run down of the features and their differences. An article that has been waiting to be written for a long time.

    In point 8 .merge() is described as in “…PHP, this function is equivalent to array_merge()”. They are similar but not strictly equivalent. .merge() affects the first input array where as array_merge() returns the two input arrays combined without affecting either of the original arrays.

    0
  14. 14

    Alberto Gasparin

    August 4, 2010 6:48 am

    Small copy-paste error:
    on extend() you have written:

    var obj1 = {one: ‘un’, two: ‘deux’}
    var obj2 = {three: ‘trois’, four: ‘quatre’}
    $.extend(arr1, arr2);

    but there is no arr1 and arr2, instead there is obj1 and obj2. Same on next snippet.
    Nice article indeed ;-)

    1
  15. 15

    The class here is req not required

    if ($(this).find(‘input’).is(‘.required[value=]‘)) {

    0
  16. 16

    Vitaly Friedman

    August 4, 2010 6:55 am

    Thanks, Alberto! Sorry about the confusion. Just fixed the typo and updated the article! Really appreciate your input.

    0
  17. 17

    Nice article. :)

    0
  18. 18

    Oliver Stretton

    August 4, 2010 7:04 am

    This has clarified a lot for me, thank you for taking the time write such a well written article =)

    0
  19. 19

    Nice article Andy. I’m not a pro at jQuery, but I am trying to learn as much as I can.

    I thought one of the major differences between live() and delegate() was that, live() attaches the handler (and I’ll use your example here) to every ‘a’ tag in #myDiv, whereas delegate() attaches one handler onto #myDiv.

    So really, for delegate(), it checks to see if an ‘a’ tag was clicked within #myDiv, and if so, run the function. One event handler. Live() in contrast ,puts an event handler on each ‘a’ that is clicked.

    Using delegate() in that example would then cut performance time down.

    Learned a couple of things though. I was not aware that live() was not chainable.

    0
  20. 20

    “A script to find all links of a certain CSS class in a document and bind an event to them now requires one line of code, not 10″

    I might rephrase this to say:

    “A script to find all links of a certain CSS class in a document and bind an event to them now requires 6000 lines of code, not 10″

    0
  21. 21

    Great post, especially for those early on in their jQuery experiences.

    —————————————————–
    However, to nitpick, your find example in no. 5 is redundant.

    $(‘#table tr.hideMe’).hide();

    would hide all TR elements with a class of hideMe, that are ancestors of a table element regardless of whether a TBODY element is present in between.

    Of course

    $(‘#table>tr.hideMe’).hide();

    would fail if TBODYwas present, but then that is why we don’t do it that way.

    0
  22. 22

    With jQuery, you don’t need document.createElement() no more. Injecting new markup is as easy as $(‘<tr><td>Some text here</td></tr>’). You will get those elements detached from body yet, but nicely wrapped in jQuery, where you can do everything you need and then .appendTo(‘target selector’)

    0
  23. 23

    You might want to look over your $.extend() code again. Your example of “extending” nested objects doesn’t actually use nested objects.

    …oh yeah, and thanks for live(). Didn’t know about that one. :)

    0
  24. 24

    Couple worthwhile notes:

    .closest() tends to perform better than .parents(), because .closest() checks after each step up the chain to see if the matched element matches the selector, and then stops, whereas .parents() selects ALL parents and THEN performs the filtering.

    If you want to iterate over a generic Array with jQuery, you should use jQuery.each(["one","two"],function() { }), rather than $(["one","two"]).each(function() { }); While the latter works, it’s not really clear why you’d wrap it in jQuery first, just for the purpose of iterating over non-DOM elements like they *were* DOM elements.

    .is() and .not() aren’t “opposites that aren’t equivalent”, they are “not opposites”. For more on this, I wrote a blog post once upon a time: http://ajpiano.com/2010/the-opposite-of-jquerys-is-method-is-not-not-it-is-is/

    0
  25. 25

    Julián Landerreche

    August 4, 2010 9:28 am

    Nice article, thanks.
    Some spotted errors:

    On click():

    - “This simply says that whenever a inside #table is clicked, alert its text content.”
    + It should read instead of .

    In real-life example for .not(), is(), :not():
    - Input element has class “req”, but then you use “.required” on the selector.

    0
  26. 26

    The first part of the “Real-Life Example” at #4 can be written much shorter (and jQuery-ish):

    $(‘#addPassenger’).bind(‘click’, function() {
    $(‘#passengersTable tbody’).append(
    $(”).append( $(”).append( $(”).attr(‘type’, ‘text’) ) )
    .append( $(”).append( $(”).attr(‘type’, ‘button’).val(‘delete’) ) )
    );
    });

    Just my 2 cents…

    0
  27. 27

    Thanks, fixed the second one. Could you please explain the first one? What exactly is wrong?

    1
  28. 28

    Folks, just buy “jQuery 1.4 Reference Guide” (http://www.amazon.com/jQuery-Reference-Guide-Jonathan-Chaffer/dp/1849510040) and read it 3 or 4 times. It covers all this (sadly, no mention of delegate, though) and much, much more.

    0
  29. 29

    Nice article…

    There is also parentsUntil which lead to another confusion… :)

    0
  30. 30

    Love the article. thanks a bunch.

    0
  31. 31

    Very nice article. I always been a bit confused on closest(), parent() and parents().

    Hope I can read another of your articles soon!

    0
  32. 32

    Amazing! Nice job! These things would help a lot in my next projects… Thanks!

    0
  33. 33

    If I understand the jQuery documentation correctly[1], “.live()” does _not_ bind to the objects themselves, instead binding to whatever context passed in the selector portion of the assignment, e.g. “$(‘ul#nav li’, $(‘ul#nav’).get(0)).live(‘click’, …)” will put the click handler on the ul#nav instead, catching bubbled-up events on the li elements.

    [1] “As of jQuery 1.4, live events can be bound to a DOM element “context” rather than to the default document root.”

    0
  34. 34

    Very very very very informative article. I did not know about these subtle differences even though I code actively in jquery. Thanks thanks thanks a lot.

    0
  35. 35

    Nice article.

    However I agree with Michael Ward that the .find() example is poor.

    As Michael points out you do not need tbody in the selector and it would work anyway.

    The beauty of .find() is that it is faster. Since a selector like $(‘#table tbody tr.hide) uses the Sizzle css/selector library. Using .find() does not have to and just looks inside the selected result set.

    0
  36. 36

    Kenneth van Rumste

    August 4, 2010 10:36 pm

    Nice article, good comparisons!

    0
  37. 37

    This articles looks new with new perspective, worth reading in my free time.

    0
  38. 38

    Very good explanation for jQuery look alike functions.

    0
  39. 39

    There is a little mistake in the first part (click) of section 4 where it says:
    “This simply says that whenever a inside #table is clicked, alert its text content.”

    as far as I understand the code it should be td instead of div:
    “This simply says that whenever a inside #table is clicked, alert its text content.”

    Very useful article though.

    0
  40. 40

    I searched a long time after an article like that. I love it. Thank you very much!

    0
  41. 41

    Wow, definitely an article that web developers & designers – novice and pro’s alike – should gloss over. Very helpful indeed, and reminds one of those forgotten yet very nifty jQuery selectors. Many thanks.

    0
  42. 42

    Wow great article. Thank you! I’d like to save it as PDF and have it handy for reference :)

    0
  43. 43

    You are wrong Maciej. That’s not general rule. English grammar is a bit different from ours. http://en.wikipedia.org/wiki/Abbreviation#Style_conventions_in_English

    -1
  44. 44

    Great! I had so many problems with bind() when new elements were injected that needed to be bound instantly, live() is a life saver in this situation :-)

    0
  45. 45

    great article

    0
  46. 46

    In Polish yes, but in English not necessarily.

    -2
  47. 47

    Rupnarayan Bhattacharya

    August 5, 2010 4:46 am

    Really good article, helped me a lot. I am a newbie to JQuery but this article really added some very usefull knowledge.

    1
  48. 48

    “Another shortfall of live() is…”

    You didn’t specify the first shortfall? Unless you’re taking the entire method to be in itself a shortfall?

    -1
  49. 49

    Very cool, so much useful content here – many thanks from a PHP-centric developer who frequently has to dabble in jQuery.

    0
  50. 50

    Great article though – very interested about filter functions.

    0
  51. 51

    I didn’t know about closest(). I’ll be using it now, thanks.

    It is accurate to say that closest() is just like find(), except it searches up the DOM tree instead of down?

    0
  52. 52

    Indeed ;)

    0
  53. 53

    A few more noteworthy points are that method equivalents of pseudo filters, like eq()/:eq, first()/:first, last()/:last, etc. are always faster, except for not()/:not. These methods simply splice an existing jQuery object, whereas the pseudo filters require revving up Sizzle.

    :not is a legit CSS3 selector so if you’re on a modern browser it’ll map directly to the native querySelectorAll.

    0
  54. 54

    Alexander Trefz

    August 5, 2010 1:10 pm

    This is old Syntax, too. $(“”, { “class”: “myclass”, “text”: “text goes here”}); would do the job since 1.4.x

    0
  55. 55

    Really very useful article.

    could u please tell us difference between
    `.is` and in `:has` ,

    0
  56. 56

    Actually, both .live() and .delegate() attach the handler to a parent node (not the target element). By default .live() attaches the handler to the document root, but as of 1.4, it can be attached to more specific context accordingly: `$(‘a’, ‘#myDiv’).live(…);` In this example, the handler would be attached to `#myDiv`.

    Surprisingly, .delegate() is just a repackaging of .live(). .delegate() just calls .live(), and adds its selector paramater as a (undocumented) forth parameter of .live(). See line 2411 of the jQuery source – http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js

    jQuery.fn.extend({

    delegate: function( selector, types, data, fn ) {
    return this.live( types, data, fn, selector );
    },

    });

    0
  57. 57

    “his simply says that whenever a inside #table is clicked, alert its text content.”
    The above line seems wrong. It should be
    his simply says that whenever a inside #table is clicked, alert its text content.

    0
  58. 58

    Chris (campino2k)

    August 5, 2010 11:53 pm

    There is no special need for adding live events, when you create Elements the way, jQuery 1.4 introduced: el = $(‘<button/> ‘, {text:’Button text’, click:function(){ /* do something on click */}} ).

    This is more conveniant and less memory intensive because there is no need to constantly watch the dom.

    0
  59. 59

    Great nice article, knew some but learned some new points…which was amazing…Thanks

    0
  60. 60

    Wow! Awesome!

    This is definitely one of the best articles on the net concerning jQuery!
    Keep on writing such amazing stuff!

    I’d rate it as A+++++ =)

    1
  61. 61

    I don’t know how many times jQuery has saved my life. Ever since I’ve used it, jQuery has became an important aspect of developing. It seriously made coding in JS so much fun. I can’t imagine a life without it. Thank you for this sweet overview.

    0
  62. 62

    Brilliant!

    0
  63. 63

    Excellent article. I learned a lot from this, rather than I used to from jquery.com. This untangles many jquery functions that could not be understood well, without this article. Please write more articles like this. I wll be looking for these, thanks.

    1
  64. 64

    The real live example can be made even shorter:

    $(‘#addPassenger’).click(function() { $(‘#passengersTable tbody’).append(‘delete’); });

    I found that different methods of the same name, like toggle (event or effect) or load (event or ajax) are much more confusing than your examples, especially if they get named attributes which are surprisingly empty (leading to the other functionality).

    0
  65. 65

    Naruki Bigglesworth

    August 7, 2010 5:46 am

    In your “parents(selector)” example in Section 1, you don’t actually have sample data with 3 levels of LI tags, so trying to test the code as shown will not color anything orange.

    This is very confusing to us newbs. :-)

    0
  66. 66

    Excellent article. You made my weekend. Would like to get some more post related to jquery. Thanks a lot. :) !

    0
  67. 67

    Haha. Yeah, confusing…

    0
  68. 68

    Wow, I didn’t realise Vitaly and the gang had published this yet – thought it was still being processed!

    Thanks for all the comments, guys. I will answer specific ones in the coming week when I get time. Glad, though, that the article was generally well received and has proved helpful.

    As some have pointed out, there are a few typos or errors. It’s a long article and I think, by the end of it, my head was mushy and I was looking for my bed, hence. I will submit corrections for these to Vitaly and hopefully he can implement them.

    On some of the points raised, yes you can append elements simply via strings, e.g. append(“hello”) but I always favour structured DOM-scripting. There are good reasons why you should create and append elements individually rather than as strings like this (this is covered in articles and books on DOM-scripting – I won’t go into detail here).

    And to the guy who said there were better candidates for confusing methods, such as the AJAX functions, yes, this is true, but that would have made for a very niche article. The methods I picked were some of jQuery’s most-used, so I thought it would be more useful to a wider audience.

    Thanks again, everyone.
    Andy

    1
  69. 69

    very neat javascript tips.. thanks for sharing..

    1
  70. 70

    Awesome article Andy! I thought I knew jQuery back to front but this is the first time I’ve heard of ‘closest’ selector.

    For optimum speed I try and use native js loops paired with a .get() call, rather than a jquery .each(). Not sure if it’s much of a gain but feels more pure.

    ^RM

    0
  71. 71

    Great article. I skimmed through it, and now taking a print out and will read it throughly over lunch.

    0
  72. 72

    Haha. Yeah, confusing article…

    0
  73. 73

    Every blog just talks about selector(s) and none explained in details. This is very helpful and now I know the difference of each selector have bookmarked it.

    Great article and keep posting more like this.

    0
  74. 74

    Once you open the page javascript start to fire up at least 50 alert about some missing brush. You better fix this!
    FF 3.* IE 7/8, Chrome 5.0

    0
  75. 75

    RT@Francesco

    Once you open the page javascript start to fire up at least 50 alert about some missing brush. You better fix this!
    FF 3.* IE 7/8, Chrome 5.0

    0
  76. 76

    Yes, those bits really are tricky. Great article !

    0
  77. 77

    Yeah I don’t know why it was doing the JS alert errors yesterday. Nothing to do with me, I think there was a site prob but it seems to have been fixed now.

    0
  78. 78

    .is() vs .not()

    It should be noted that “.has()” would be the opposite of “.not()”

    0
  79. 79

    colinbashbash – true, but filter() can be used in the same way and, since the article covered filter() in detail, I stuck with that.

    0
  80. 80

    Awesome tuts… Thanks

    0
  81. 81

    The example of parents(selector) was so bad, that I stopped reading the article.

    0
  82. 82

    @Natrium – it would appear from the kindly positive feedback that you are in the minority – a minority which, apparently, can criticise but not cite reasons for the criticism or suggest alternatives.

    1
  83. 83

    what a brilliant article. I am using Jquery since last year but I could understand the difference between these methods only reading this article.

    0
  84. 84

    Virendra Dugar

    May 6, 2011 2:23 am

    I found a nice article which explains the difference between bind(), live() and delegate method.

    http://jquerybyexample.blogspot.com/2010/08/bind-vs-live-vs-delegate-function.html

    3
  85. 85

    Okay, well…i have played around with the parents() method and got absolutely NO results at all?

    Then i moved onto the closest() method and again got absolutely NO results…so…..thats where i stopped as i am now more frustrated with jQuery then i ever was!

    0
  86. 86

    @Neil – you don’t really provide us with any info as to HOW you were trying to use these. All of the methods you claim to be frustrated with work fine, for example:

    JS
    $(function() { $(‘a’).closest(‘div’).css(‘border: ‘solid 1px #f00′); });

    HTML
    <div><p><a href=’#’>hello</a></p></div>

    This code gives the div a red border, as it is the closest div (from a parental/ancestral perspective) to the link.

    0
  87. 87

    Great =D

    0
  88. 88

    Re-creating a jQuery object from a DOM element when you already had a collection of jQuery objects is wasteful. To explain, you have this:

    $($(‘#element1′).parents(‘#element2′).get(0))

    When you can do the same thing, without the extra overheard, with this:

    $(‘#element1′).parents(‘#element2′).eq(0)

    0
  89. 89

    Great stuff! Loads of clarification, thanks for sharing this will certainly be useful.

    I wrote some examples for using jQuery $.each could be useful to some people starting out, thought I would share it if that’s OK. http://www.revillwebdesign.com/jquery-foreach/

    Cheers!

    0

↑ Back to top