Let's traverse through DOM Tree - Few advanced notes on jQuery Selectors

Background:

We have already seen different jQuery selectors (see earlier post) and used a few examples to select one/multiple Dom element(s). But what about travarsing the whole DOM tree. can we select inversely?  can we select a dropdown without knowing its value? Lets look at some of the advanced jQuery selectors and a few in-built jQuery methods that can in this regard.


Vertically traversing through DOM:

Think about nested DOM elements, can we get the child elements of an element after selecting an element using any of the jQuery selectors? the answer is yes. jQuery have in built methods that allows us to traverse through DOM and get child elements.

To get all child elements of an element we can use .children() method, which return an array of elements that are 1st level child of that element.So .children() method does not gives those elements which are child of these 1st level elements. The .children() method allows us to pass a selector in order to get specific child element(s).
As we know most of the jQuery methods return an jQuery object, and we can call multiple methods in chain (method chaining, see post) We can always traverse the entire DOM tree by looping through each element that .children() method gives and again calling the .children() method for each one of them, but it is not recommended.

To travarse the entire DOM tree and find a specific child element at any level we can use the .find() method. For .find() method to work, we have to pass a selector as parameter. So unlike other DOM travarsal methods this one have a mandatory parameter. If we want to select all the elements we can pass in the universal selector '*'

Similarly we can get the parent element as well through .parent() method which will give the immediate parent element. In order to get all the parent elements all the way up to the document's root element (), we have .parents() method.

Let's look at the following example on these methods:

<html title="html title">
    <head>   
        <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
    </head>
    <body title="body title">       
        <div Class="level1" title="parentdiv">       
        <div id="firstChild" Class="level2"></div>       
        <div id="div1" Class="level3">Test1</div>      
        <div id="div2" Class="level3">Test2</div>   
        <div id="div3" Class="level3">Test3</div>
        </div>
        <div id="secondChild" Class="level2">
        <div id="div4" Class="level3">Test4</div>
        <div id="div5" Class="level3">Test5</div>  
        </div>
        <div id="thirdChild" title="thirdChild" Class="level2">
        <div id="div6" Class="level3">Test6</div>  
        </div>
        </div>
        <br/>
        <div id="childrenoutput"></div>
        <br/>
        <div id="findoutput"></div>
        <br/>
        <div id="parentoutput"></div>
        <br/>
        <div id="parentsoutput"></div>
        <input type="button"id="myBtn"value="Click Me">
    </body>
</html>
<script type="text/javascript">
    function init(){
    $("#myBtn").click(function(){
    var childs= $(".level1").children();
   
    var childrenOutput = "";
    for(var i=0;i<childs.length;i++){
    childrenOutput += childs[i].id + ",";
    }
    $("#childrenoutput").text("child count : " + childs.length + ", ids :" + childrenOutput);       
       
    var allChilds = $(".level1").find("div");
    var findOutput = "";
    for(var i=0;i<allChilds.length;i++){
    findOutput += allChilds[i].id + ",";
    }   
    $("#findoutput").text("child count : " + allChilds.length + ", ids :" + findOutput);

    var parent = $("#div1").parent();
    $("#parentoutput").text("parent id : " + parent[0].id);
    var allparents = $("#div6").parents();

    var parentsOutput = "";   
    for(var i=0;i<allparents.length;i++){
    parentsOutput += allparents[i].title + ",";
    }
    $("#parentsoutput").text("child count : " + allparents.length + ", titles :" + parentsOutput);
    });
    }
    $(document).ready(init);

</script>

Horizontal traversing the DOM:

As discussed above, we can traverse the jQuery tree vertically (using children(), find(),parent(), parents() methods), we can also traverse sideways and get the elements that are at the same level of the DOM tree i.e the elements that share the same parent.
In order to traverse side ways jQuery provides many methods like :

  • siblings()
  • next()
  • nextAll()
  • nextUntil()
  • prev()
  • prevAll()
  • prevUntil()

All these methods are applied on a jQuery selector, and finds horizontal elements on the output of the selector.



The siblings() method finds all the elements which have the same parent.So, the code $("ul li.element").siblings() will return all the elements that are the siblings of the element selected by the selector. We can pass an optional selector inside the siblings() method which allows to filter among the siblings.


The behaviour of the other methods mentioned above are very similar. these methods behaviour is:
  • next() - Selects the immediate next sibling of the element
  • nextAll() - Selects all the next siblings of the element
  • nextUntil() - Takes a selector as input and selects all siblings next upto the selector
  • prev() - Selects the immediate previous sibling of the element
  • prevAll() - Selects all the previous siblings of the element
  • prevUntil() - Takes a selector as input and selects all previous siblings upto the selector
Let's look at The following example:

<html>
<head>   
  <style>
  div {    float: left;  }
  span {    color: red;  }
  </style>
  <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<div>
  <ul>
    <li>Cricket</li>
    <li class="element">Football</li>
    <li>Badminton</li>
    <li>Hockey</li>
    <li class="lastElement">Baseball</li>
  </ul>
</div>
<script>
$("ul li.element").siblings().append( "<span> siblings |</span>" );//appends a span for all li except Football

$("ul li.element").next().append( "<span> next |</span>" );//appends a span for li with Badminton
$("ul li.element").nextAll().append( "<span> nextall |</span>" );//appends a span for li with Badminton,Hockey & Baseball
$("ul li.element").nextUntil("ul li.lastElement").append( "<span> next Until |</span>" );//appends a span for li with Badminton,Hockey

$("ul li.element").prev().append( "<span> Prev |</span>" );//appends a span for li with Cricket
$("ul li.lastElement").prevAll().append( "<span> Prev All |</span>" );//appends a span for li with Cricket,Football,Badminton & Hockey
$("ul li.lastElement").prevUntil("ul li.element").append( "<span> Prev Until |</span>" );//appends a span for li with Hockey,Badminton
</script>
</body>

</html>

Invert Selection:

So far we have seen different selectors and ways to find the parent and child element(s) of a DOM element. Another very important method for selecting DOM elements is .not(). With this method we can select elements that does not match the selector.
The method syntax is : 

$(":not(selector)")

Here the selector is a mandatory parameter, i.e. we have to use some selector to use this method. This is mostly used with another selector to select everything other than the specified element.
For example:

$("div:not(.row)")//Select all

elements except those with class="row"



The :eq Selector:

Many jQuery selectors, returns an array of elements. So If we want to find the element that is present in the nth index of the selected set, we can easily do this using the :eq selector. Obviously we could have loop through the selected elements and find out the desired element but that is not a good practice.

The :eq selector works on the output of any existing selector, i.e it works on an array of elements. Since JavaScript array uses 0 based index, the :eq selector will return the element based on 0 based index.

For example, Let's consider the code $( "td:eq(1)"). We assume that "td" selector returns 5 elements. the :eq(1) will execute on that array of 5 elements and since it is a 0 based index, this will return the 2nd element from the array not the first.

We can pass a -ve value as parameter to this method as well. In that case it will get the element with that index from the last. So in the above example if we write $( "td:eq(-1)") then the return element will the one which is the 1 th element from the last i.e the 4th element.

Note: If you are using a jQuery version before 1.8, -ve index is not supported.


:nth Child with index & odd/even childs:


We discussed about finding the children of a specific element with .children() method. we can also find element(s) using the .find() method. To get the a certain child element we do not have to loop through all the child elements, we can dynamically find the nth member of all the child. jQuery provides another utility built in method :nth-child(). The code $("ul li:nth-child(2)") will select the elements which matches the $(ul li) selector, then will return the child which is in 2nd position. In this case the index starts with 1, so it is very much different from the :eq() method we discussed earlier.
One more important note for this method is this method is, it considers all the child elements and does not use any selector to filter among the child elements.

We can pass either a number to get the element in that position among the child elements, or we can pass "even" or "odd" keywords in order to get all the even/odd elements among the childs.
Let's have a look at the below example:

<html>
<head>   
    <style>
        div {
        float: left;
        }
        span {
        color: red;
        }
    </style>
    <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
    <div>
        <ul>
        <li>Cricket</li>
        <li>Football</li>
        <li>Badminton</li>
        <li>Hockey</li>
        <li>Baseball</li>
        </ul>
    </div>
    <div>
        <ul>
        <li>A</li>
        <li>B</li>
        <li>A</li>
        </ul>
    </div>
    <div>
        <ul>
        <li>1st</li>
        <li>2nd</li>
        <li>3rd</li>
        <li>4th</li>
        </ul>
    </div>
    <script>
        $( "ul li:nth-child(even)" ).append( " - Even" );
        $( "ul li:nth-child(1)" ).append( " - 1st" );
        $( "ul li:nth-child(odd)" ).append( " - Odd" );
    </script>
    </body>

</html>

Comments

Popular posts from this blog

Ways to select DOM element(s) - a guide to jQuery Selectors

Handling Events in jQuery – Few Advanced Notes and Faqs