Operating on Selections

Contact Us or call 1-877-932-8228
Operating on Selections

Operating on Selections

jQuery has many methods that you can use to operate on selections, There are methods to refine selections by filtering or selecting descendant elements, traverse to neighboring elements or parent elements, and read/write values of various properties.

The $.fn Methods

Although $ is a jQuery function, remember that functions are also objects, so that a function can contain properties and methods. jQuery adds properties and methods to $ after it is created. In particular, the code that loads jQuery defines a property, fn, or the $ object. The fn object, in turn, contains numerous methods, like the addClass method that we have already seen.

Technically speaking, the fn object is used as the prototype for jQuery collections, which means that every jQuery collection contains everything that is in the fn object.
In documentation and online tutorials, the various collection methods are referred to as $.fn.xyz, such as $.fn.addClass.

Refining and Filtering Selections

Sometimes you have a selection that contains more than what you're after; in this case, you may want to refine your selection. jQuery offers several methods for zeroing in on exactly what you're looking for.

Selector Contexts

The $ function can accept an optional second parameter, context, that is a jQuery object to use as a starting point for the selection process. This context provides a means to limit the search within a specific node or a jQuery object containing a set of nodes. This is great when you have a very large DOM tree and need to find, for example, all the a tags within a specific part of the DOM tree.

Let's say we wanted to remove all the nested tables in the DOM, here's what we could do:

/*
get all 'table' tags and put them in a variable called $tables.
$tables now becomes a "jQuery object".
*/
var $tables = $('table');

//outputs the # of tables in the DOM
console.log($tables.length);

/*
get the inner tables in $('table', $tables), notice the 2nd argument, $tables, which is the "context" in which jQuery is making the selection.
*/
var $innerTables = $('table', $tables);

//filter out, using the "not" operation, all the inner tables from $tables
$tables = $tables.not($innerTables);

//now prints the # of tables without the inner tables
console.log($tables.length);

Now, in finding the inner tables to remove, the parameter to the "not" operation is the selection of all 'table' tags within the elements in the $tables object itself (in other words, within all the 'table' elements already selected). Therefore, $tables is the context in the case.

In pure JavaScript terms, the engine is going to perform getElementsByTagName('table') on each element in $tables, and return those elements so that they can be used in the "not" method. This approach becomes useful when you have a collection that you have refined to a point where it would no longer be easy or efficient to specify it with a single selector string, and you then want to use it as a context for further selection.

Refining and Filtering Methods

Most of the refining methods accept a selector as a parameter:

method( selector )

The selector is a string containing a selector expression to match the current set of elements against. By default, for most of the refining operations, the selector string operates in the context of the document, that is, the selector is evaluated from the root level, not the level reached by the selection. So, for example, using the not function to exclude a subset of elements, $('table').not('table') will not remove nested tables. It will result in an empty set, since the 'table' selector for the not operation will be applied from the root of the document, not from the level reached by the original query, and we will remove exactly the same elements we originally found.

The find method, for example, uses the current collection as the context, so that the selector string is evaluated using the current collection as the starting point. So, $('ul').find('ul') will find only inner lists.

Additional Method Overloads for Refining and Filtering Methods

Some of the refining/filtering functions accept additional forms of the parameter list. The full set of overload possibilities is below.

method( function(index) )

A function used as a test for each element in the set. this is the current DOM element. If the function returns true, the element is included in the result collection.

method( element(s) )

An element or array of elements to match the current collection against. The matching is done using an equality test. The result will only include items that are in the set of elements, in effect producing the intersection of the filtered current collection with the set of elements.

method( jQuery object )

An existing jQuery object to match the current set of elements against. Similar to using elements, but using jQuery collection instead, again producing the intersection of the filtered current collection with passed-in collection.

Method Description Parameters
filter filters the collection to only include elements that match the passed-in selector selector, function, elements, jQuery
find finds descendant elements that match the parameter; uses the current collection as the context for a selector selector, elements, jQuery
children finds all children, optionally filtered by a selector none, selector
first finds the first element in the collection none
last finds the last element in the collection none
eq(n) finds the nth element in the collection index
is tests the current collection and returns true if any element in it matches the selector (technically speaking, this isn't a filtering method, but that is the category that jQuery's documentation lists it under) selector, function, elements, jQuery
has finds all elements in the current collection that have at least one descendant that matches the selector selector, elements
not returns a new collection containg all the original elements except elements that match the selector selector, function, elements, jQuery

Refining Methods are NOT Mutators

The original selection is not modified by the operation, but a new, modified set is returned. For example, if we wanted to find li elements and eliminate those with the special class, we could do:

var $items = $('li');
var $notSpecialIitems = $items.not('.special');

The $items collection is unchanged by the not operation -- a new collection is created and returned. If we wanted to use just one variable, we would need to do the following (recognizing that in this case it would be simpler to just use a single chained statement instead of two separate statements, but that would not make this concept clear):

var $items = $('li');
$items = $items.not('.special');

Code Sample:

jqy-concepts/Demos/refining-selections.html
---- C O D E   O M I T T E D ----
<script>
$(document).ready(function() {
	// div.foo elements that contain <p>'s
	$('div.foo').has('p').addClass('big');
	
	// h1 elements that don't have a class of bar
	$('h1').not('.bar').addClass('italic');
	
	// unordered list items with class of current 
	$('ul>li').filter('.current').addClass('redText');
	
	// just the first unordered list item
	$('ul>li').first().addClass('yellowBg');
	
	// the sixth
	$('ul>li').eq(5).addClass('italic');	
});
</script>

---- C O D E   O M I T T E D ----
</head>
<body>
<div class="foo">foo div w/o p</div>
<div class="foo"><p>foo div w/ p</p></div>
<h1 class="bar">h1 bar</h1>
<h1>h1</h1>
<ul>
	<li class="current">current and the first</li>
	<li>not current</li>
	<li class="current">current</li>
	<li>not current</li>
	<li class="current">current</li>
	<li>not current, but the sixth</li>
	<li class="current">current</li>
	<li>not current</li>
</ul>
</body>
</html>

Chaining

If you call a method on a selection and that method returns a jQuery object, you can continue to call jQuery methods on the object.

Chaining Example

$('#content').find('h3').eq(2).html('new text for the third h3!');

If you are writing a chain that includes several steps, you (and the person who comes after you) may find your code more readable if you break the chain over several lines.

Formatting Chained Code

$('#content')
	.find('h3')
	.eq(2)
	.html('new text for the third h3!');

If you change your selection in the midst of a chain, jQuery provides the $.fn.end method to get you back to your original selection.

Restoring Your Original Selection Using $.fn.end

Code Sample:

jqy-concepts/Demos/restoring-selection.html
<html>
<head>
<script src="../../jqy-libs/jquery.js"></script> 
<script>
$(document).ready(function() {
	$('#content')
			.find('h3')
			.eq(2)
					.html('new text for the third h3!')
			.end() // restores the selection to all h3's in #content
			.eq(0)
					.html('new text for the first h3!');
});
</script>
</head>
<body id="content">
<h3>First</h3>
<h3>Second</h3>
<h3>Third</h3>
<h3>Fourth</h3>
</body>
</html>
Chaining is extraordinarily powerful, and it's a feature that many libraries have adapted since it was made popular by jQuery. However, it must be used with care. Extensive chaining can make code extremely difficult to modify or debug. There is no hard-and-fast rule to how long a chain should be -- just know that it is easy to get carried away.
Next