Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is(':first') returns different (wrong?) results for what should be the same element. jsFiddle inside

http://jsfiddle.net/garnwraly/sfrwU/2/

given HTML of only

<li>
    <button id="bam">click</button>
</li>

and this script

$('body').on('click', 'button', function (e) {
    //console.log( e.currentTarget == $('button')[0] ); //true;
    //console.log($('li').is('li:first')); //true

    console.log($(e.currentTarget).parent().is('li:first')) //false
    console.log($('button').parent().is('li:first')); //true
    console.log($($('button')[0]).parent().is('li:first')); //false
});

why is $(e.currentTarget).parent().is('li:first') false?

like image 282
CheapSteaks Avatar asked Apr 20 '13 00:04

CheapSteaks


2 Answers

After step debugging through the jQuery code as this ran, this turns out to be an issue with the way the jQuery() method is used within the is() method. As we know, you can pass a context into the method, and internally, this context is being used with the is() method (and is being set differently for the various selectors).

When $(e.currentTarget) is used, the context is set to the button that triggered the event. While when $('button') is used, the context is set to the Document object. This makes sense when you think of how these selectors need to be scoped.

Here is the relevant part of the is() method:

jQuery( selector, this.context ).index( this[0] ) >= 0

Based on that, when run as $(e.currentTarget), the call to the jQuery() method is evaluation to:

jQuery("li:first", "button#bam").index( this[0] ) >= 0

Which is obviously returning -1, and reporting as false

like image 123
ryanbrill Avatar answered Oct 04 '22 04:10

ryanbrill


I think it may be that :first only cares about matching - in the case that the jQuery object is constructed from a DOM element, there's no selector matching going on. Note that

console.log($(document.getElementById('bam')).is(':first'));

also logs false.

I don't feel that the behavior is correct, and a bug should probably be logged, but even if it worked properly I don't think that in this case testing :first really does any good. If you use .parent() to navigate up the DOM to the parent node starting from a single element, then it's pointless to ask whether the parent is the first element - there'll always be a parent (except from the DOM root of course), and always just one.

If you do it with :first-child, which would actually be interesting but not necessarily relevant, then it works as one might expect because :first-child is actually about the structure of the DOM. The :first qualifier is just about being the first matched element.

like image 40
Pointy Avatar answered Oct 04 '22 02:10

Pointy