JavaScript - - By Baljeet Rathi

A Comprehensive Look at jQuery DOM Traversal

Separate elements of code in hospital drips. A metaphor for DOM traversal.

DOM traversal means that once you have selected an element or elements on a web page, you can move through the page elements relative to your initial selection. During this process, you can either replace the original selection with a new one or add and subtract elements from it.

In this article we will look at the available methods for jQuery DOM traversal, and see how the library provides many ways for us to easily select elements based on their relationships to other elements in the page.

Filtering Elements

Let’s begin by looking at how to filter a selection down to something more specific. You can filter elements based on a lot of conditions like their position with respect to other elements and whether or not they have a specific class. Most of the time, you will end up with fewer elements selected than you began with.

Here is a list of the different filtering methods:

  • eq — This method reduces the set of matched elements to the one that is located at the index you specified. The indexing is zero based. Therefore, to select the first element, you will have to use $("selector").eq(0). Starting with version 1.4, you can provide a negative integer to begin counting elements from the end instead of the beginning.

  • first and last— The first method will return just the first element from the set of matched elements while last will return the last element from the set of matched elements. Neither of these methods accepts any arguments.

  • slice — If you are looking for all elements in a set whose index lies within a given range, you can using slice(). This method accepts two arguments. The first one specifies the starting index from which the method should start slicing and the second argument specifies the index at which the selection should end. The second argument is optional and if omitted results in the selection of all elements whose index is greater than or equal to start.

    See the Pen eq and slice methods by SitePoint (@SitePoint) on CodePen.

  • filter — This method will reduce your set of elements to those that either match the selector or pass the criteria set by you in the function that is passed to this method. Here is one example of this method with selectors:

    $("li").filter(":even").css( "font-weight", "bold" );
    

    You could also select the same elements using a function:

    $("li")
    .filter(function( index ) {
       return index % 2 === 0;
    })
    .css( "font-weight", "bold" );
    

    You can also use the function to perform more complicated selections like:

    .filter(function( index ) {
     return $( "span", this ).length >= 2;
    })
    

    This would have only selected elements that have at least two span tags.

    See the Pen filter method by SitePoint (@SitePoint) on CodePen.

  • map — You can use this method to pass each element in your current selection through a function, ultimately creating a new jQuery object containing the return values. The returned jQuery object itself contains an array and you can use the get method on it to work with a basic array.

    See the Pen map method by SitePoint (@SitePoint) on CodePen.

Traversing the DOM

Consider a scenario where you know the selector you can use to access various elements but you need to work with the parents of all those elements. Additionally, the parents have no specific class or tag which is common to all of them. The only thing they have in common is the fact that they are all parents of elements which you have access to. I have faced a similar situation more than a few times.

jQuery provides a lot of useful methods to access the parents, children or siblings in such cases. Let’s go over all of them one by one:

  • children — This method allows us to get the children of each element in our set of elements. Those children can optionally be filtered by a selector.

  • find — This method will get all the descendants of each element in your set of matched elements filtered by a selector or element. In this case, the selector argument passed to find() is not optional. If you want to get all the descendants, you can pass the universal selector ('*') as an argument to this method.

    As you can see in the demo, children() only underlines the direct children of our paragraphs but find() adds a background to all its descendants with a matching selector.

    Demo

  • parent — This method will get the parent of each element in the current set. The parents can optionally be filtered using a selector.

  • parents — This method will get all the ancestors for each element in your set. It also accepts an optional selector argument to filter the ancestors. The difference between parent() and parents() is that the former one only traverses a single level up in the DOM tree while parents() goes all the way up to the document’s root.

  • closest — This method will get the first element that matches the given selector by testing the element itself and then traversing up in the DOM tree. There are two significant differences between parents() and closest(). While parents() begins the traversal from the parent of the element, closest() begins it from the element itself. Another difference is that closest() will only traverse the DOM tree until it finds a match while parents() will keep moving upward until it reaches the document’s root element.

    Consider these two lines of code taken from the following demo:

    $("i").closest("span").css("background", "yellow");
    $("b").parent().css("color","blue");
    

    Now note that the word “italic” in the last paragraph did not have any ancestor with a <span> tag. Therefore, its background was unchanged.

    Similarly, the second line changed the color of <span> tags enclosing our bold words to blue. Now, in the last case, the whole paragraph was the parent of the <b> tag and therefore it all turned blue.

    Demo

  • siblings — This method gets the siblings of each element in the set of matched elements. You can optionally provide a selector as an argument to only get siblings with the matching selector.

  • prev — This method will get the immediately preceding sibling of each element in our set. If you have provided a selector, the method will only select an element if it matches that selector.

  • prevAll — This method will get all the preceding siblings of each element in our set. Just like the other methods, you can provide a selector to filter the returned elements.

  • next — This method will only get the immediately following sibling of the matched elements. If a selector is provided, it will get the sibling only if it matches.

  • nextAll — This method will get all the siblings which are successors of the elements in our set. The sibling can be optionally filtered by providing a selector.

    Consider these two lines of code from the demo:

    $("selector").next(".nextall").css("color","orange");  
    $("selector").nextAll(".nextall").css("color","red");
    

    You will see that none of the items in the list has the orange color. That’s because the next immediate sibling of our reference item does not have the nextall class.

    See the Pen next, nextAll, previous and previousAll in jQuery by SitePoint (@SitePoint) on CodePen.

    I would like to once again mention that when you provide a selector to next() and prev() , they won’t look for all next and previous siblings to find the first one that matches the given selector. They will just look at the immediately preceding and following sibling and if those siblings don’t have the matching selector, an empty jQuery object will be returned.

More Methods Related to DOM Traversal

When traversing the DOM, you may face situations where you need to add more elements to your selection which are not related to your original set, or you need to revert back to your previous set of elements. jQuery provides a few functions that you can use to perform all these tasks.

  • add — This method will create a new jQuery object that will contain our new elements added to the list of existing ones. Keep in mind that the there is no guarantee that the new elements will be appended to your existing collection in the order in which they were passed to the add method.

  • addBack — jQuery maintains an internal stack that it uses to keep track of changes to your set of elements. Calling any of the traversal methods pushes a new set of elements on that stack. If you want to work with both the previous and new set of elements you can use the addBack method.

    For the first case under the addBack section, we begin by selecting the paragraph and then calling children(). In the second case, after calling children() we also call addBack(). Calling addBack() adds the second paragraph to our selection and we then apply the red border to it.

    See the Pen add and addBack in jQuery by SitePoint (@SitePoint) on CodePen.

  • end — This method will end the most recent filtering operation and return your set of elements to its previous state. It can be useful in situations where you want to manipulate some elements related to your current set of elements, revert to your original set and then manipulate a different set of elements.

    In the demo below I begin by using .find("b") to select all the <b> tags and then once I have changed their color to green, I call .end(). This call returns us to our previous selection from where I again select all the <i> tags.

    Demo

  • contents — If you want to get all the children including text and comment nodes of all the elements in your set, you can use the contents method. You can also use this method to get the contents of an <iframe> if the <iframe> is on the same domain as your web page.

  • not — If you have a large set of elements and only want a subset of those elements that don’t match a given selector, you can use not(). From version 1.4 onward, the method can take a function as an argument as well to test each element against certain conditions. Any element which matches those conditions will be excluded from the filtered set. In the following demo, I have added a border to all elements that don’t have the not-selected class using .not(".not-selected"). Similarly, in the next set of divs, I have also set the color of all elements whose height is not greater than 120px to purple.

    See the Pen .not() in jQuery by SitePoint (@SitePoint) on CodePen.

Conclusion

All these methods in jQuery provide an easy way for us to traverse from one set of elements to another. Since a few of these methods are very similar to each other, I recommend that you pay special attention to them. Knowing the difference between parents() and closest() or next("selector") and nextAll("selector").eq(0) can probably save you a few hours of trouble in certain situations.

I hope you liked this article. If you have any tips that you would like to share with other readers, please comment below!

This article was peer reviewed by Joan Yin and Chris Perry. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Sponsors