Bug Tracker

Opened 11 years ago

Closed 11 years ago

Last modified 10 years ago

#11315 closed bug (fixed)

Problems with delegate() and :first in nested elements with equivalent classes

Reported by: dos-one Owned by: dmethvin
Priority: low Milestone: 1.8
Component: event Version: 1.7.1
Keywords: Cc:
Blocked by: Blocking:


If you have a nested hierarchy of DOM elements, all having the same class. .delegate() using the :first pseudo selector has problems. Please see the JSBin below.


It appears that only the topmost element is found. This presents major problems when dealing with tree like dom structures. Further, if you switch between jQuery 1.6.4 and 1.7.1 in the JS Bin, you'll notice that everything works fine with 1.6.4 so this appears to be a clear regression.

Change History (15)

comment:1 Changed 11 years ago by dmethvin

Yes, this did change. The 1.7 event delegation code now uses .is() internally rather than having its own implementation. The .is() code is always rooted at the document so that selector always returns the first element in the document.

Regardless, positional selectors like :first are non-standard and so they have to go through the JavaScript Sizzle engine rather than either the browser's native-code matchesSelector or our own quick optimization for tag#id.class. As a result any selector like .class:first is horrendously inefficient; it has to get the complete list of elements with that class and see if there are any. And it does that for every element from the event.target to the delegation point.

So, my preference would be to just say that positional selectors aren't supported in delegated event handlers. We can add more code to fix the regression but it will still be slow and unadvisable.

comment:2 Changed 11 years ago by dmethvin

Status: newopen

comment:3 Changed 11 years ago by dos-one

I understand your concerns regarding performance, although in some cases this is a very useful selector and the performance is not relevant. What would be an equivalent workaround? Further, doesn't it seem odd to say that you can only use the :first selector in some places that take a selector but not others?

We noticed this bug because we have a nested hierarchy (similar to a folder tree in Windows Explorer) so we have the same dom elements nested within each other. We can't just delegate to .class because there are multiple nested elements that all contain that class and we want the first one in relation to a given scope. (Further, we're using Backbone View's events pattern so we're somewhat limited in what we can do)

comment:4 Changed 11 years ago by dmethvin

If they are all first children of their parent you could use :first-child, that is a standard selector and definitely a better semantic match as well. It may be possible to make :first work and I'm looking at it, but I cringe to think of what the browser does for that case.

comment:5 Changed 11 years ago by dos-one

So I've updated the JSBin (jsFiddle was doing their cloud move) to show our scenario with first-child, and we get some unfortunate event bubbling. So if you click "b" you also see that "a" got an event. Perhaps I'm doing something wrong though!


In any case, if you guys do decide to go forward with a fix please definitely leave a comment.

Thanks for your quick replies!

comment:6 Changed 11 years ago by dmethvin

Yes, you would want to stop propagation, right?

comment:7 Changed 11 years ago by dos-one

Well, we could, but in our situation that's really no different than just delegating to .class and stopping propagation. The nice thing about :first was that it didn't bubble the event when in a nested hierarchy like that.

(If you switch the JS bin to use :first and then use 1.6.4 that's the lack of bubbling we were relying on)

In any case, if this becomes an issue we cannot work around we'll likely just stick to the 1.6.x series. Thanks very much for your time!

comment:8 Changed 11 years ago by dmethvin

The nice thing about :first was that it didn't bubble the event when in a nested hierarchy like that.

Not true. When you click on the innermost link, the event continues to bubble from #c to #b to #a and requires jQuery to do all the selector-matching at each element; it just didn't match the selector in 1.6.4. Nobody is ever calling .stopPropagation() on your behalf.

comment:9 Changed 11 years ago by dos-one

You're quite right, I could have said that in a more technically correct way. But I hope you can see that the point I was trying to make was that the callback functions for the outer elements never got called when you click the inner element because, as you say, the selector didn't match. This is the behavior we were relying on, and this is the behavior that changed between versions.

comment:10 Changed 11 years ago by dmethvin

Component: unfiledevent
Milestone: None1.8
Priority: undecidedlow

We should either fix or wontfix for 1.8.

comment:11 Changed 11 years ago by dmethvin

Owner: set to dmethvin
Status: openassigned

comment:12 Changed 11 years ago by Dave Methvin

Resolution: fixed
Status: assignedclosed

Fix #11315. Selector for .on() is relative to delegateTarget.

This fixes a regresssion from 1.6.4. Be aware that nearly every place that this bug comes into play, the selector in use is incredibly inefficient.

Changeset: 94e744aec9d25bb64a3cb72c3b81dd95e94d3955

comment:13 Changed 11 years ago by dmethvin

#11993 is a duplicate of this ticket.

comment:14 Changed 11 years ago by dmethvin

#12114 is a duplicate of this ticket.

comment:15 Changed 10 years ago by anonymous

What version is this fixed in?

Note: See TracTickets for help on using tickets.