Bug Tracker

Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#9747 closed bug (invalid)

:first selector behaves inconsistently in chained find() invocations — at Version 5

Reported by: hallettj Owned by:
Priority: low Milestone: 1.next
Component: selector Version: 1.6.1
Keywords: Cc:
Blocked by: Blocking:

Description (last modified by Rick Waldron)

Affects every version of jQuery that I tested: 1.2.6, 1.3.2, 1.4.4, 1.5.2, 1.6.1.

Reproduced in Chrome beta under Ubuntu 11.04.

Steps to reproduce:

  1. Create HTML structure with multiple elements, such as a list.
  2. Construct a jQuery selector that selects some or all of those elements, such as $('li').
  3. Use a find() invocation on the previously selected elements with a selector that matches some nested element and include the expression ":first" in that selector. For example, $('li').find('a:first').

Expected results:

The first matched nested element is returned from the find() invocation. In the case of a list where nested elements are single anchor tags, the anchor tag in the first list element is returned.

Actual results:

Every nested element matching the given selectors is returned. It is as though ":first" has no effect on result of the find() invocation.

jsfiddle test case:

If I combine both selectors into one jQuery() call instead of using a chained find() invocation then the result is as I expect. For example, $('li a:first') returns a single anchor tag: the one in the first list item. But $('li').find('a:first') returns every anchor tag in every list item - assuming that each list item has at most one anchor tag.

Maybe this is intended behavior. But it is really not what I expected. If this is intended behavior it would be helpful to have a note in the documentation for :first, :eq, or find() that explains the discrepancy.

Change History (5)

comment:1 Changed 11 years ago by Rick Waldron

Component: unfiledselector
Priority: undecidedlow
Resolution: invalid
Status: newclosed

I reduced your test even further and there is nothing inconsistent about it: http://jsfiddle.net/rwaldron/XBM2w/

comment:2 in reply to:  1 Changed 11 years ago by hallettj

Replying to rwaldron:

I reduced your test even further and there is nothing inconsistent about it: http://jsfiddle.net/rwaldron/XBM2w/

The inconsistency is that I expected $(selectorA + " " + selectorB) to be equivalent to $(selectorA).find(selectorB) in every case. Finding out that that is not true is very surprising. If this is really not the way that find() is supposed to work there should be an explanation in the documentation as the current behavior is not obvious.

comment:3 Changed 11 years ago by Rick Waldron

The description in the api is quite clear:

Description: Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.

comment:4 Changed 11 years ago by hallettj

What is not clear is the scope of the selectors in the find() call. Consider that, at least in a case where every 'li' has an 'a' descendant, $('li a:first') and $('li:first a') produce the same results. This implies that ':first' scopes over the entire result set, not just to the results of traversing an individual 'li' tag. So when I run $('li').find('a:first') I expect ':first' to limit the entire result set to one element. But instead I get three elements. This time ':first' *is* scoped to the results of traversing an individual 'li' tag. To my view the scope of ':first' is inexplicably inverted when used in find().

I understand now that find() probably makes separate selections against the descendants of each 'li' tag and that ':first' is probably scoped to the results each individual selection. But I was only able to come to that conclusion because of my investigation of find() behavior for this issue report.

The documentation for ':eq()' says,

Select the element at index n within the matched set.

It does not give any indication that in the case of find() there will be a separate "matched set" corresponding to each element in the original selection, and that ':eq()' will apply to each such set individually before those sets are unioned and returned. But the actual behavior of ':first' and ':eq()' in find() seems to indicate that this is a more accurate description.

I do not believe that the docs provide any information to clarify this point. Furthermore, in my opinion the behavior as it is implemented is counter-intuitive and is a bug.

Last edited 11 years ago by hallettj (previous) (diff)

comment:5 Changed 11 years ago by Rick Waldron

Description: modified (diff)
Keywords: needsdocs added

Just because you says it's a bug, does not make it a bug.

Note: See TracTickets for help on using tickets.