Skip to main content

Bug Tracker

Side navigation

#12094 closed bug (duplicate)

Opened July 17, 2012 12:58PM UTC

Closed July 17, 2012 02:44PM UTC

Last modified July 17, 2012 06:34PM UTC

Incorrect events triggering order on programmatic .focus()

Reported by: xmorel Owned by:
Priority: low Milestone: None
Component: event Version: 1.7.2
Keywords: ie6 ie7 ie8 ie9 ie10 Cc:
Blocked by: Blocking:
Description

The normal workflow of moving focus from one element to an other, is to first trigger blur() on the first field, then trigger focus() on the second one. This is especially important to determine whether focus remains within a group of fields or gets out of those (a timeout can be set up on blur(), cancelled on focus(), if the timeout triggers then the focus has left the group's fields).

This normal workflow works in all situations: when the user tabs from one field to the next, when the user focuses the second field by clicking, and when focus is programmatically moved via HTMLElement#focus

But now when using jQuery#focus: http://jsfiddle.net/FDjFc/1/

The test case sets up the following:

  • Assumes the first field is focused as source
  • Logs (prints) when the first field is blurred
  • Logs when the second field is focused

Focus can be moved by pressing the [TAB] key (keypress), clicking on the second field (mouse), pressing the [DOWN] key (programmatic, DOM) and pressing the [UP] key (programmatic, jQuery).

Case has been tested in:

  • Safari 5.1
  • Firefox 13
  • Opera 12
  • Chrome 19
  • Internet Explorer 9
  • Internet Explorer 8

In ''all'' of those:

  • on keypress, a blur event is triggered on the first field, then a focus even is triggered on the second field
  • on mouse, a blur event is triggered on the first field, then a focus even is triggered on the second field
  • on programmatic DOM, a blur event is triggered on the first field, then a focus even is triggered on the second field

Divergences happen *only* in programmatic jQuery:

  • Internet Explorer 8 and 9 will trigger focus, blur, then focus again
  • Other browsers trigger focus on the second field, then blur on the first one.

Which means it is ''not possible'' to use the pattern outlined at the top if fields are going to be programmatically focused ''via jQuery'' (or inversely focusing a field programmatically ''via jQuery'' is going to break the pattern).

Attachments (0)
Change History (8)

Changed July 17, 2012 02:44PM UTC by dmethvin comment:1

component: unfiledevent
keywords: → ie6 ie7 ie8 ie9 ie10
priority: undecidedlow
resolution: → duplicate
status: newclosed

Focus and blur are miserably quirky in IE all the way up to IE10. We've discussed the issues with the IE team and they plan to look at it, but in the meantime I think there is very little we can do to rectify this from within jQuery.

I tried to deal with several of these issues such as #6705 during the 1.7 era but couldn't find an acceptable solution. Better to have it fire twice than not to fire at all--even though that's EXACTLY what the native handler does when the element already has focus.

Changed July 17, 2012 02:44PM UTC by dmethvin comment:2

Duplicate of #6705.

Changed July 17, 2012 02:52PM UTC by xmorel comment:3

_comment0: Erm… I'm sorry but did you actually read the bug or did you just read the title, assume it was an IE bug and tag it? The IE-fires-twice issue is a minor side-note, the bigger issue and the one which is ''broken'' is that jquery fires the blur and focus events ''in the wrong order'' when programmatically focusing a field, that's got nothing to do with IE, it happens this way in every single browser I tested.1342536813856411

Erm… I'm sorry but did you actually read the bug or did you just read the title, assume it was an IE bug and tag it? The IE-fires-twice issue is a minor side-note, the bigger issue and the one after which the report is titled is that jquery fires the blur and focus events ''in the wrong order'' when programmatically focusing a field, that's got nothing to do with IE, it happens this way in every single browser I tested.

Changed July 17, 2012 03:31PM UTC by dmethvin comment:4

Well I thought I read the bug, but I must have missed an important plot point around chapter 12.

So if I may do Cliff Notes here, you are saying:

  • **DOM:** A.focus() with B in focus fires blur-B, focus-A.
  • **jQuery:** $A.focus() with B in focus fires focus-A, blur-B.

Except in IE, where it's more complicated. Is that right?

And, although it wasn't stated, jQuery's behavior has been like this ever since version 1.1 or so.

Changed July 17, 2012 05:32PM UTC by xmorel comment:5

DOM: A.focus() with B in focus fires blur-B, focus-A.

and so will user-generated (non-programmatic) focus changes, yes.

jQuery: $A.focus() with B in focus fires focus-A, blur-B.

Yes, with the consequence of breaking a widespread pattern for handling focus within a group of fields.

And, although it wasn't stated, jQuery's behavior has been like this ever since version 1.1 or so.

I only tested 1.6 and 1.7, but wouldn't be surprised if it were older, so I'll trust you on that.

Changed July 17, 2012 06:05PM UTC by dmethvin comment:6

The break/fix is in the exact same place as the one I marked a dup, it's here:

https://github.com/jquery/jquery/commit/6a670df9e9b9e5cd278b390a2e99ac179307a4e9#L0R527

The idea was to try and use the native method to get similar behavior, but we can't do that easily because of delegation issues, IE focus inconsistencies, and problems with already-focused elements not firing focus.

Again, a patch is welcome, but it will still require handling all the special cases where people expect handlers to fire when they natively don't. I wasn't able to figure out a bulletproof solution when I was working on that code.

The workaround short of a patch is to fire DOM focus manually (e.g., $(el)[0].focus() instead of $(el).focus() and deal with its quirks instead of jQuery's quirks.

Changed July 17, 2012 06:25PM UTC by xmorel comment:7

_comment0: > The workaround short of a patch is to fire DOM focus manually \ \ Sure, and that's what we implemented, but it's rather frustrating to look for fuck-ups in your code, and end up realizing select's broken after all, in a way which diverges from all native behavior.1342549564791667
_comment1: > The workaround short of a patch is to fire DOM focus manually \ \ Sure, and that's how we fixed it, but it's rather frustrating to look for fuck-ups in your code, and end up realizing select's broken after all, in a way which diverges from all native behavior.1342549881154411
_comment2: > The workaround short of a patch is to fire DOM focus manually \ \ Sure, and that's how we fixed it, but it's rather frustrating to look for fuck-ups in your code, and end up realizing select's broken after all, in a way which diverges from all native behavior. \ \ edit: although \ \ > The idea was to try and use the native method to get similar behavior, but we can't do that easily because of delegation issues \ \ for focus/blur, does that not happen just when the events are delegated? We're using direct binding — as in the demo case I posted — so the events ''should'' go through native should they not?1342550013971842
_comment3: > The workaround short of a patch is to fire DOM focus manually \ \ Sure, and that's how we fixed it, but it's rather frustrating to look for fuck-ups in your code, and end up realizing select's broken after all, in a way which diverges from all native behavior. \ \ edit: although \ \ > The idea was to try and use the native method to get similar behavior, but we can't do that easily because of delegation issues \ \ for focus/blur, does that not happen just when the events are delegated? We're using direct binding — as in the demo case I posted — so the events ''should'' go through native should they not? Or is the issue with the morphing-on-trigger, which converts the native events and blows up the ordering?1342550063814695
The workaround short of a patch is to fire DOM focus manually

Sure, and that's how we fixed it, but it's rather frustrating to look for fuck-ups in your code, and end up realizing select's broken after all, in a way which diverges from all native behavior.

edit: although

The idea was to try and use the native method to get similar behavior, but we can't do that easily because of delegation issues

for focus/blur, does that not happen just when the events are delegated? We're using direct binding — as in the demo case I posted — so the events ''should'' go through native should they not? Would the issue not be with the morphing-on-trigger, which converts the native events and blows up the ordering, rather than with the change you link to?

Changed July 17, 2012 06:34PM UTC by dmethvin comment:8

The source is there if you'd like to make suggestions. Maybe you could solve the problem. I've explained why we can't do EXACTLY what the native method does, it's not what people expect to happen. They want their focus/blur handler to fire when they trigger an event, regardless of whether the element is in focus/blur at the moment.