Anant Dabhi
Anant Dabhi

Reputation: 11134

Jquery :first selector give second element instead of first

I want select first row from any cell so I just wrote javascript like.

  var curcontrol = $("#cellno_111");
    var firsttd= $(curcontrol).parents("table tbody tr:first");
    alert($(firsttd).text());

And my table is below

<table id="idTable_1" border="1px" width="97%" class="tblDragTable" data-numberofrows="2" data-numberofcolumns="2">
    <tbody>
    <tr id="trno_10">
        <td class="tblCell" id="cellno_100">0</td>
        <td class="tblCell" id="cellno_101">0</td>
        </tr>
    <tr id="trno_11" height="1">
        <td class="tblCell" id="cellno_110" width="1">1</td>
        <td class="tblCell selectedCell" id="cellno_111" width="1">1</td>
        </tr>
    </tbody>
</table>

when I use find() it giving me correct result

 var curcontrol = $("#cellno_111");
  var firsttd= $(curcontrol).parents("table tbody").find("tr:first");

But I just want to know why the above code return second tr instead of first tr

HERE IS MY JSBIN http://jsbin.com/lisozuvade/1/watch?html,js,output

Upvotes: 0

Views: 173

Answers (4)

Tom D&#39;Hulster
Tom D&#39;Hulster

Reputation: 123

If I'm not mistaken, the parent hierarchy of cellno_111 is: trno_11 -> tbody -> table

In your first example, the first tr parent cellno_111 finds is trno_11 and not trno_10. It does not have a trno_10 parent.

The reason it does work with find(), is because you select the tbody and then search for the first tr child the tbody has.

Upvotes: 1

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93601

The reason why it fails is because calling parents with a filter of table tbody tr will only match the immediate parent TR. The other TR falls outside of the ancestors so :first will match the only TR it finds.

If you try this you will see what is going on:

alert($(curcontrol).parents('table tbody tr')[0].outerHTML);

returns this:

    <tr id="trno_11" height="1">
        <td class="tblCell" id="cellno_110" width="1">1</td>
        <td class="tblCell selectedCell" id="cellno_111" width="1">1</td>
    </tr>

then try this:

alert($(curcontrol).parents('table tbody')[0].outerHTML);

which returns this:

<tbody>
    <tr id="trno_10">
        <td class="tblCell" id="cellno_100">0</td>
        <td class="tblCell" id="cellno_101">0</td>
    </tr>
    <tr id="trno_11" height="1">
        <td class="tblCell" id="cellno_110" width="1">1</td>
        <td class="tblCell selectedCell" id="cellno_111" width="1">1</td>
    </tr>
</tbody>

JSFiddle: http://jsfiddle.net/TrueBlueAussie/j28g27m1/

So your first example only looks at the ancestors (one TR) and returns the first match. The second example looks further back up the tree, then finds all TRs in the tbody then chooses the first one.

A preferred, slightly faster, way would be to use closest() and find()

e.g.

var curcontrol = $("#cellno_111");
var firsttd= $(curcontrol).closest("tbody").find("tr:first");

or faster yet (as selectors are evaluated right-to-left):

var curcontrol = $("#cellno_111");
var firsttd= $(curcontrol).closest("tbody").find("tr").first();

e.g. http://jsfiddle.net/TrueBlueAussie/j28g27m1/1/

Upvotes: 3

David Fregoli
David Fregoli

Reputation: 3407

You're asking for parents of #cellno_111, only that tr is.

Also keep in mind that :first is like .first() as it filters to the first element in the set of matched elements, it has nothing to do with being the first child of something. If you want multiple elements, which are first children you should use :first-child.

.parents(table tbody tr:first): query the parents of the element for a tr which is inside of table and tbody, then pick the first

.parents("table tbody").find("tr:first"): query the parents of the elements for a tbody which is inside a table, then find all trs inside of it, then pick the first of them

PS: I suggest using closest instead of parents as the go-to DOM navigation method for ancestors; most of the times it's way more practical and easier to understand.

Upvotes: 3

Laurent S.
Laurent S.

Reputation: 6947

Actually, you need to understand what each selector is doing. Try with several console.log, you'll see:

$(curcontrol).parents();

This return a set of elements. In this set, there is only 1 tr, the parent of your curcontrol td tag.

You can indeed filter this specific set by adding a extra filter :

$(curcontrol).parents("table tbody tr:first");

But as I just explained, the original set only contains a single TR, so the first one returned is actually the only one returned.

Your find() approach is different, you specify a specific (parent) element and with the find() you search trough children, which explains in this case the correct behaviour.

Upvotes: 1

Related Questions