Building the New Next and Prev jQuery Methods
A jQuery CSS selection hierarchy is separated by the space character. The following code doesn't select just any paragraph. But the paragraph within a table, within a tr, within a td tag. These "within's" are indicated by the often overlooked space character: which in its own right is an instruction to the internal CSS selector processor.
$("table tr td p");
We know that when we select an HTML element using a CSS selector, there is a distinction between the hierarchy (elements that lead to the target element) and the target element itself, which is the last selector in the hierarchy:
$("table tr td"); // Select all td's in all tables (table and tr will not be selected)
$("table tr td:last input"); // Select all input elements within the last td in a table
That sounds simple. But there is one more detail that is often overlooked.
Selecting next and previous children
Being mindful of the type of the target element is not necessary here. All children, regardless of type count. This may sound like a small detail but it can cause confusion if not fully understood.
After I learned the basics of jQuery methods next and prev, and conceptually understood them, I still sometimes find myself running into some inconsistencies when using them. Below I break down the problem into basic blocks anyone can easily understand.
The documentation says: Just use next and prev to iterate to the next or previous element counting from the currently selected target element.
But here is the key. The previous element does not have to share the type of the selected element.
In both cases the jQuery selector ignores the type of the target element. The type of the element becomes irrelevant. Let's take a look.
Considering we have this HTML:
$("table").prev(); // Select the table, then select the previous table.
$("table").prev().css("background", "red"); // Select the table, then select the previous table and color its background red. Note, the first table will be affected, but not the second one. If the page contains only one table, the red background will not be applied to it at all. If the page contains two tables, only the first one will be affected (because it is the previous table counting back in hierarchy from the second table.) The first table is selected too, but because there is no previous table before it, there is nothing to apply the CSS code to -- and method prev() would not return any elements in that case at all.
$("table tr td").prev(); // Select each td in any and all tables, and select only the previous td counting from it. In a way, the target element is now indicated by the prev method. Not the last element (td) in selector's hierarchy as it was in previous examples.
Note in the code above, the target element is no longer td. So this time, the prev method selects the previous td (not table, like in the example we've just seen above it.) The target element that is selected becomes the previous td itself.
But here is the catch. The method prev would select the previous element within the table. Even if it is not of type td! For example, it would select th too. As long as it is the previous child.
What happens here? The type of the target element is not preserved. Similarly, if you used the next() method, the next element of any type in the hierarchy would be selected (counting from the currently selected one, which, only in this case any and all td elements in any and all tables on the page.) Whatever is the last element, that is the element we will be iterating forward and backward with these methods.
In normal circumstances, next and prev are used to iterate through the next and previous elements of the same type. Or at least it may only seem so. What happens if the previous element is not of the type td? Will it not be selected? Consider this HTML:
<span>A text span</span>
What will happen if we select a paragraph (<p>) and then use prev to go a step back? Will it still select the previous element even though it is of type span? Let's do an experiment:
$("p").prev().css("background", "red"); // What will happen?
What will happen is that span turns red. This proves that the type of the element prev selects is completely irrelevant. What I mean is, that if you have a hierarchy of the same elements (let's say a number of <p>'s or a series of LI tags in a row -- that happens often!) then you most definitely should use next and prev. And the outcome will always be predictable. But if the elements are of not the same type, then the results are not predictable. Remember we do live in a dynamic DOM world (who knows? Sometimes DOM is modified on the fly, and the HTML structure changes, so your next/prev methods will no longer select quite the same element before and after the DOM change!)
So why am I breaking this down in such detail? That's because it is important. We are not dealing just with next and prev methods. But with the structure of HTML itself, which can have any form, either determined by us or not. That's the key. It can be dynamic. And in this one case I outline below, it can definitely be confusing. Let's see.
In this case only the p tag is colored red. Why can this be confusing? Because the CSS selector $("span") does not even talk about paragraphs. And the next element can be anything.
Most people don't pay any attention to this and try to "calibrate" their selectors on the fly. Something doesn't work? Add or remove a space, try another method, swap the methods around, etc. But knowing that the selector does not retain the type of the target element when it comes to next and prev methods is great knowledge in our hands.
I see a situation in which it would be useful to be able to select the previous or next element of the same type. However, jQuery itself does not offer such a solution to us. We could use a filter like this:
But that will select a previous <p> element only if it is indeed a <p> element. If the previous element is not a p element, then none will be selected even if there are paragraph elements prior to it (past a few non-p elements). And it will not "skip over" any number of non-p elements to find one of type <p>.
What can we do? Let's create our own plugin that does that. Now that would be interesting. Let's do it! We will use the $.extend function to create our plugin. It will select all next elements within the hierarchy, skipping over however many non-p elements. In other words, it will find that next element no matter what, if it exists within the same child hierarchy.
Preparation for our custom plugin: The type-aware "next" method.
We want to create an alternative to the existing jQuery methods next and prev. But with a custom condition. The next element must be of the same type as the one specified with the selector itself. I called the new methods next_type and prev_type.
// Select the next p tag after the one being selected
<p id = "para"></p>
typeof(document.getElementById("para")); // returns "object"
typeof($("p#para")); // still returns "object", not "paragraph" that we need
document.getElementById("para").tagName; // Now it returns P... just what we need
jQuery simplified getting tagName by offering its own way of getting the value. In order to do that we will use the method $.fn.prop('tagName'); But first let's do a brief experiment:
<p id = "para">hello</p>
Keeping this HTML in mind, let's do the following to select all elements using the star (*) selector:
var all = $("*"); // Select absolutely all elements
We have 5 HTML elements, so the length of the returned object should say 5, right?
alert(all.length); // 14!
Wrong! That's because the star (*) selector selects everything, including the tag, the <style> tags and even the <doctype> tag. Everything.
We can use a trick to avoid this situation. Naturally we want to grab only the 5 elements from within the assumed tag, which most of the time we don't have to work with anyway, because it is the main container for all tags.
In order to do that, we will correct the $("*") selector by adding context to it:
var onlybody = $("body"); // Create a new context out of <body>
var all = $("*", onlybody); // Search only within the context (the <body> tag)
Now all.length returns 5. Just as expected. There are only 5 elements within the body.
What is the key to this? Let's do this quick example:
obj.P = 10; // assign custom property P to the object
alert(obj.P); // retrieve the property P
In addition you can use the following syntax to add associative entries to an object-array:
obj["P"] = 10; // assign using brackets
alert(obj.P) // 10
And to check if "P" exists in that object, we can use the in keyword:
alert("P" in obj); // There is a property named "P" -- returns true
alert("A" in obj); // returns false -- no property named "A" was found
Note that this won't work for values:
alert("10" in obj); // false
alert(10 in obj); // false
These tips will become useful later as we build the plugin.
var all = $("*", $("body")); // Search for any elements within body
first_element.tagName; // returns "P"
$(first_element).prop("tagName"); // returns "P"
$(first_element).attr("id"); // returns "para"
Let's see how we can loop through the entire list of returned elements from a CSS selection and display each element's tag name:
for (var i = 0; i < all.length; i++)
var type = el.tagName; // get tag name of this element (P,SPAN,etc.)
alert(type); // display the type in an alert box
This code will display 5 alert boxes showing the types of the elements that were selected in the following sequence: P,B,SPAN,P,P. Because this is the order in which the HTML elements appear, in the earlier example. So we have 3 P tags, 1 B tag and a SPAN tag. For other selections of course this will be different.
Going back to where it all began: we were going to create a plug in that chooses next or previous elements with a catch: the next or previous element must be of the same type compared to the one that is being selected by jQuery's command such as $("p") or even $("p,span") which selects elements of both types P and SPAN.
We will need both next_type and prev_type functions. They are quite similar. Based on what we just learned above let's write the plugin and discover these interesting techniques in terms of practical implementation.
First we will need to write a function that browses through the entire list of array entries, identifies its tag name and compares it with the tag name that was passed to it. It then returns a "next" element on the same list with index greater than the one that was passed to it. In other words, it returns the next element of type X, where X is whatever we are looking for:
// next_type: get next element(s) of selected type(s)
// -- select all next p's (counting from first selected)
// -- in the same order as they appear on the page.
// -- regardless of their position within parents
// Helper function
// Find 1 next element of type matching that of the seed
function next_of_type(arr, types, brk)
var ret = ;
// A very interesting way to list through the entire custom object using for-loop directive
// As you can see for(var i=0;i<10;i++) is not the only format we can use when using for.
// The property var will become the actual property name, types is the object.
for (var property in types)
var i = 0;
var ri = 0;
if (i > types[property])
if (property == arr[i].tagName)
ret[ri++] = arr[i];
// We have to wrap ret in $() object. This way we return a series of jQuery objects for further processing by the methods in the chain. Had we not done it, we would not be able to use the method next_type as part of a method chain.
// Extend jQuery with the new plugin method
var arr = ;
var types = new Object; // first occurances of type
var types_i = 0;
// Identify the first occurrence of the type at index. This is interesting. We are gathering the type of the element and only store it once in the types array, even if it continues to occur in the received array containing all selected elements. So if the type is already stored at types["P"] (for paragraph for example) we no longer need to store it. Finally, the types object
if (this.tagName in types == false)
types[this.tagName] = index;
// Collect this item to be a return value later
arr[arr.length] = this;
// Use the helper function we previously built. This is the core of plugin.
return next_of_type(arr, types, !flood);
// Using the new plugin,
// Let's try to select some of the B, P and SPAN elements
// -- and then select all next elements of the same type (excluding the original)
In the example just above, notice that I passed true to next_type method. This is the flood parameter. If it is set to true, all next elements of the same type (until the very end of the web page) are selected. In other words the selection "floods" the rest of the elements on the page. If it is set to false, only the following (the first next) element is selected.
Adding prev_type method is similar. It does pretty much the same thing, except it iterates the objects from bottom up.
I created a jsFiddle to demonstrate it. Both examples are provided here for educational purposes only.