159

When I want to get, for example, the 3rd level parent of the element I must write $('#element').parent().parent().parent() Is there a more optimal method for this?

shift66
  • 11,760
  • 13
  • 50
  • 83
Artur Keyan
  • 7,643
  • 12
  • 52
  • 65
  • 2
    I want to give only number (Level) and get element, because my element may not have any calss id or name – Artur Keyan Aug 17 '11 at 13:31
  • 1
    If you plan on reusing this functionality, the optimal solution is to make a jQuery plugin. – zzzzBov Aug 17 '11 at 13:35
  • 3
    See http://jsperf.com/jquery-get-3rd-level-parent for some performance comparisons – a'r Aug 17 '11 at 14:06
  • 1
    Another good tool is the ".closest()" function. $('li.item').closest('div') will give you the DIV that is the closest ancestor of the li.item. Good for when you don't know how many levels up the element is, but you DO know its tagname/class/something else. – Graham Aug 17 '11 at 18:42

13 Answers13

284

Since parents() returns the ancestor elements ordered from the closest to the outer ones, you can chain it into eq():

$('#element').parents().eq(0);  // "Father".
$('#element').parents().eq(2);  // "Great-grandfather".
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • can I using this $('#element').parents()[2]? or it must by with eq(2) – Artur Keyan Aug 17 '11 at 13:44
  • 1
    this will not work for multiple element selections, a safer way would be: `$('.element').first().parents().eq(num);` – zzzzBov Aug 17 '11 at 13:44
  • 8
    @Arthur, using `[2]` will return the underlying DOM element, using `eq(2)` will return a jQuery object. – Frédéric Hamidi Aug 17 '11 at 13:47
  • 1
    @zzzzBov, very true, but there will only be one element selected in the questioner's case (because he matches an id). – Frédéric Hamidi Aug 17 '11 at 13:48
  • If you do a look up on an id "#element" it would only ever return a single element as that's how ID lookups work, they return the first element with that ID in the dom. If on the other hand you did "div#element" or a class selector you would be right. – Henry Aug 17 '11 at 13:48
  • @Henry Garle, I was speaking for the generic selector `$(...some selector...)`, rather than ids specifically. – zzzzBov Aug 17 '11 at 13:50
  • @Artur, that won't give you the jQuery object, but the HTML node. – Alex Turpin Aug 17 '11 at 13:51
  • Sneaky Frédéric, I saw that comment edit! :P I'll try not to be too bitter about your answer being posted after mine and being accepted with the same content :P – Henry Aug 17 '11 at 13:54
  • @Henry, yup, but I realized the questioner was matching the id before reading your comment, honest :) – Frédéric Hamidi Aug 17 '11 at 13:55
  • Good, but please don't use `.parents([selector]).eq(0)`, use `.closest([selector])`. – orlp Aug 17 '11 at 19:17
  • @nightcracker, that's not always possible: `closest()` includes the element itself in its search, unlike `parents()`. – Frédéric Hamidi Aug 17 '11 at 19:19
  • @Frédéric Hamidi: Ah good spot, I didn't know that. I would always consider `.closest()` before considering `.parents().eq(0)` though, because it's more readable, but, once again good spot :) – orlp Aug 17 '11 at 19:21
  • @nightcracker, I actually used the `0` index as an example for this specific question. In general, I never use `parents().eq(0)`, since `parent()` does the job better. – Frédéric Hamidi Aug 17 '11 at 19:30
29

Depends on your needs, if you know what parent your looking for you can use the .parents() selector.

E.G: http://jsfiddle.net/HenryGarle/Kyp5g/2/

<div id="One">
    <div id="Two">
        <div id="Three">
            <div id="Four">

            </div>
        </div>
    </div>
</div>


var top = $("#Four").parents("#One");

alert($(top).html());

Example using index:

//First parent - 2 levels up from #Four
// I.e Selects div#One
var topTwo = $("#Four").parents().eq(2);

alert($(topTwo ).html());
Henry
  • 2,187
  • 1
  • 15
  • 28
  • I now this way, but I want to give level – Artur Keyan Aug 17 '11 at 13:34
  • 3
    Read further down the answer and all shall be revealed! (I've given you level examples) – Henry Aug 17 '11 at 13:37
  • This works nicely for all other kinds of selectors. For example, if you want the list of all parents and parents of parents with a certain class, this will return them. – darksky Aug 01 '17 at 22:21
9

You could give the target parent an id or class (e.g. myParent) and reference is with $('#element').parents(".myParent")

Joseph Marikle
  • 76,418
  • 17
  • 112
  • 129
7

Didn't find any answer using closest() and I think it's the most simple answer when you don't know how many levels up the required element is, so posting an answer:
You can use the closest() function combined with selectors to get the first element that matches when traversing upwards from the element:

('#element').closest('div')    // returns the innermost 'div' in its parents
('#element').closest('.container')    // returns innermost element with 'container' class among parents
('#element').closest('#foo')    // returns the closest parent with id 'foo'
Dane
  • 9,242
  • 5
  • 33
  • 56
6

A faster way is to use javascript directly, eg.

var parent = $(innerdiv.get(0).parentNode.parentNode.parentNode);

This runs significantly faster on my browser than chaining jQuery .parent() calls.

See: http://jsperf.com/jquery-get-3rd-level-parent

a'r
  • 35,921
  • 7
  • 66
  • 67
  • By "significantly faster", we're looking at about an order of magnitude in terms of speed difference (running jQuery 1.10.1 on Chrome 51). Definitely worthwhile implementing if you're tuning for speed. – Iain Fraser Jul 06 '16 at 07:57
3

If you have a common parent div you can use parentsUntil() link

eg: $('#element').parentsUntil('.commonClass')

Advantage is that you need not to remember how many generation are there between this element and the common parent(defined by commonclass).

azro
  • 53,056
  • 7
  • 34
  • 70
ashishyadaveee11
  • 1,021
  • 15
  • 17
3

It's simple. Just use

$(selector).parents().eq(0); 

where 0 is the parent level (0 is parent, 1 is parent's parent etc)

zatatatata
  • 4,761
  • 1
  • 20
  • 41
3

Just add :eq() selector like this:

$("#element").parents(":eq(2)")

You just specify index which parent: 0 for immediate parent, 1 for grand-parent, ...

MBO
  • 30,379
  • 5
  • 50
  • 52
  • This way is the fastest way to get job done. Here's the benchmark to prove it: https://jsperf.com/jquery-get-element-s-nth-parent – bekliev Oct 11 '19 at 09:00
3

If you plan on reusing this functionality, the optimal solution is to make a jQuery plugin:

(function($){
$.fn.nthParent = function(n){
  var $p = $(this);
  while ( n-- >= 0 )
  {
    $p = $p.parent();
  }
  return $p;
};
}(jQuery));

Of course, you may want to extend it to allow for an optional selector and other such things.

One note: this uses a 0 based index for parents, so nthParent(0) is the same as calling parent(). If you'd rather have 1 based indexing, use n-- > 0

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • I think you will find this part faster:`var p = 1 + n; while (p--) { $p = $p.parent(); }` and IF you want to change to 1 based, Javascript being "falsey" you can use: `while (n--) { $p = $p.parent();} ` saving a conditional check – Mark Schultheiss Aug 17 '11 at 19:30
  • @Mark Schultheiss, It's not just about speed, it's about reliability too. What happens to your function if someone ignorantly calls `nthParent(-2)`? Your example is broken. – zzzzBov Aug 17 '11 at 19:33
  • OR just return `(function($) { $.fn.nthParent = function(n) { return $(this).parents().eq(n); }; }(jQuery)); ` – Mark Schultheiss Aug 17 '11 at 19:39
  • @Mark Schultheiss, again, reliability. *My* function returns the nthParent for *every* element in the selection, *your* function returns the nth element in the list of `parents` which will be incorrect for selections with more than one element. – zzzzBov Aug 17 '11 at 19:43
  • true regarding the -2, and as in your example using `var p = n >? (1 + n):1; ` instead would return the first parent in that case rather than "nothing" - or where it breaks the loop in my example. SO, it probably should be: `(function($) { $.fn.nthParent = function(n) { var $p = $(this); if (!(n > -0)) { return $() }; var p = 1 + n; while (p--) { $p = $p.parent(); } return $p; }; }(jQuery)); ` if you do not want to return anything. – Mark Schultheiss Aug 17 '11 at 20:38
  • I considered checking negatives and selecting children, using `0` for self-reference, at which point `nthParent` would be a misnomer. – zzzzBov Aug 17 '11 at 20:45
1

As parents() returns a list, this also works

$('#element').parents()[3];
DidThis
  • 491
  • 6
  • 5
1

you can also use :

$(this).ancestors().eq(n) 

ex: $(this).ancestors().eq(2) -> the parent of the parent of this.

Mouna Cheikhna
  • 38,870
  • 10
  • 48
  • 69
1

using eq appears to grab the dynamic DOM whereas using .parent().parent() appears to grab the DOM that was initially loaded (if that is even possible).

I use them both on an element that has classes applied it to on onmouseover. eq shows the classes while .parent().parent() doesnt.

0

You could use something like this:

(function($) {
    $.fn.parentNth = function(n) {
        var el = $(this);
        for(var i = 0; i < n; i++)
            el = el.parent();

        return el;
    };
})(jQuery);

alert($("#foo").parentNth(2).attr("id"));

http://jsfiddle.net/Xeon06/AsNUu/

Alex Turpin
  • 46,743
  • 23
  • 113
  • 145