30

Is there a cheap method to select the deepest child of an element ?

Example:

<div id="SearchHere">
  <div>
    <div>
      <div></div>
    </div>
  </div>
  <div></div>
  <div>
    <div>
      <div>
        <div id="selectThis"></div>
      </div>
    </div>
  </div>
  <div>
    <div></div>
  </div>
</div>
handris
  • 1,999
  • 8
  • 27
  • 41
fehrlich
  • 2,497
  • 2
  • 26
  • 44
  • Not meant as a criticism, but I'm fascinated by why you'd want to? – David Thomas Sep 24 '10 at 14:26
  • 1
    For all those that are finding this through the search engines, I updated the gist from jonathan with the improved version from patrick dw. Also expanded the instructions a little bit. You can find it here: [jQuery deepest plugin gist](https://gist.github.com/1014671 "jQuery deepest plugin gist") –  Jun 08 '11 at 15:54
  • This jquery plugin may help: https://github.com/martinille/jquery.deepest.js – Martin Ille Dec 29 '22 at 03:04

7 Answers7

30

EDIT: This is likely a better approach than my original answer:

Example: http://jsfiddle.net/patrick_dw/xN6d5/5/

var $target = $('#SearchHere').children(),
    $next = $target;

while( $next.length ) {
  $target = $next;
  $next = $next.children();
}

alert( $target.attr('id') );

or this which is even a little shorter:

Example: http://jsfiddle.net/patrick_dw/xN6d5/6/

var $target = $('#SearchHere').children();

while( $target.length ) {
  $target = $target.children();
}

alert( $target.end().attr('id') ); // You need .end() to get to the last matched set

Original answer:

This would seem to work:

Example: http://jsfiddle.net/xN6d5/4/

var levels = 0;
var deepest;

$('#SearchHere').find('*').each(function() {
    if( !this.firstChild || this.firstChild.nodeType !== 1  ) {
        var levelsFromThis = $(this).parentsUntil('#SearchHere').length;
        if(levelsFromThis > levels) {
            levels = levelsFromThis;
            deepest = this;
        }
    }
});

alert( deepest.id );

If you know that the deepest will be a certain tag (or something else), you could speed it up by replacing .find('*') with .find('div') for example.

EDIT: Updated to only check the length if the current element does not have a firstChild or if it does, that the firstChild is not a type 1 node.

user113716
  • 318,772
  • 63
  • 451
  • 440
  • 1
    Awesome! Works perfectly! I've also encapsulated this in a jQuery plugin. Here: https://gist.github.com/714851 – Jonathan Nov 25 '10 at 03:28
  • @jonathanconway - Updated my answer with what is likely a more efficient version. – user113716 Nov 25 '10 at 12:23
  • 1
    I've created a more robust [jQuery plugin: .deepest()](http://codepen.io/gfullam/pen/BNoZWG) based on the original answer which works just liked you'd expect, returning a collection of the deepest children of each element in the set of matched elements, optionally filtered by a selector. It is fully chainable and respects the `.end()` method. View it on [CodePen](http://codepen.io/gfullam/pen/BNoZWG), [JSFiddle](http://jsfiddle.net/gfullam/f8wuc3f8/), [Gist](https://gist.github.com/geraldfullam/3a151078b55599277da4) – gfullam May 06 '15 at 18:13
5

Here's a slight improvement on the answer from @user113716, this version handles the case when there are no children and returns the target itself.

 (function($) {

    $.fn.deepestChild = function() {
        if ($(this).children().length==0)
            return $(this);

        var $target = $(this).children(),
        $next = $target;

        while( $next.length ) {
          $target = $next;
          $next = $next.children();
        }

        return $target;
    };

}(jQuery));
russellfeeed
  • 617
  • 8
  • 10
  • +1, because i just had to copy/past to get exactly what i need, get nested object or just initial object. Thank! – Georgio Oct 03 '16 at 18:08
3

I don't think you can do it directly but you can try

var s = "#SearchHere";
while($(s + " >div ").size() > 0)
    s += " > div";
alert( $(s).attr('id') );
Loïc Février
  • 7,540
  • 8
  • 39
  • 51
1

This chainable one-liner worked for me, but it assumes there is only one leaf node in the hierarchy below.

jQuery("#searchBeginsHere")
  .filter(function(i,e){ return jQuery(e).children().size() === 0; })
Mike S
  • 51
  • 4
0

Version to get deepest for each leaf.

http://jsfiddle.net/ncppk0zw/14/

var found = $('#SearchHere *');

for (var i = 0; i < found.length; i++) {
    if (i > 1) {
        if (found[i].parentNode !== found[i-1]) {
            // Deepest. Next element is other leaf
            console.log(found[i-1]);
            continue;
        }
        if (i == found.length-1) {
            // Deepest. Last element in DOM tree
            console.log(found[i]);
        }
    }
}
Dmitry
  • 877
  • 1
  • 16
  • 30
0

This will find the deepest element of type "param" on the page. Useful if you are looking for the deepest , or whatever.

function deepest_child(param) {
    var element_list = $(param)
    var depth = 0
    var deepest_element
    element_list.each(
        function (index) {
            this_depth = $(this).parents().length
            if (this_depth > depth) {
                depth = this_depth 
                deepest_element= $(this)
            }
        })  
    return deepest_element
}
talkingtoaj
  • 848
  • 8
  • 27
0

There is Simple Way with CSS

just add space between Classes or Ids

#SearchHere #selectThis{
      width:100px;
      height:50px;
      background-color:red;
    }
    
    #SearchHere .blueItem{
      width:100px;
      height:50px;
      background-color:blue;
    }
    
    #SearchHere .lastItem{
      width:100px;
      height:50px;
      background-color:cyan;
    }
    
    #SearchHere .middleItem{
      width:100px;
      height:50px;
      background-color:black;
    }
    
<div id="SearchHere">
    <div>
        <div class="blueItem">
            
        </div>
    </div>
    <div class="middleItem"></div>
    <div>
        <div>
            <div>
                <div id="selectThis"></div>
            </div>
        </div>
    </div>
    <div class="lastItem">
        <div></div>
    </div>
</div>
rahman
  • 95
  • 8
  • Even if it works, it misses the point of the question. The classes and IDs are there to understand the problem, not to be used. – fehrlich Apr 23 '23 at 08:20