Bug Tracker

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#12094 closed bug (duplicate)

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).

Change History (8)

comment:1 Changed 7 years ago by dmethvin

Component: unfiledevent
Keywords: ie6 ie7 ie8 ie9 ie10 added
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.

comment:2 Changed 7 years ago by dmethvin

Duplicate of #6705.

comment:3 Changed 7 years ago by xmorel

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.

Last edited 7 years ago by xmorel (previous) (diff)

comment:4 Changed 7 years ago by dmethvin

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.

comment:5 Changed 7 years ago by xmorel

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.

comment:6 Changed 7 years ago by dmethvin

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.

comment:7 Changed 7 years ago by xmorel

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?

Last edited 7 years ago by xmorel (previous) (diff)

comment:8 Changed 7 years ago by dmethvin

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.

Note: See TracTickets for help on using tickets.