#1 ✓resolved
Scott Hyndman

Using arrow keys, Firefox fires dropdown onchange event after element loses focus, others don't

Reported by Scott Hyndman | April 13th, 2008 @ 10:57 PM

Problem encountered on Mac Firefox and Mac Safari

The 'change' event does not fire on combobox selects when changing selection with the keyboard. Events fire properly with select-one lists and select-multiple lists.

I have attached an example which runs without modification.

Fix (Updated with Safari fix described below)

This is a new registerCallback method for Abstract.EventObserver. It seems to be working alright for me.

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        // XXX: [scott] this case is added to fix select-one combos
		case 'select-one':
          var sz = element.readAttribute('size');
          if(!sz || parseInt(sz) <= 1) { // will match null, 0 or 1 
            // do not use onElementEvent as the event callback directly. some browsers dispatch keypress
            // before changing the value on the select, so we need to defer the call until after the change
            Event.observe(element, 'keypress', (function() {
              // bind() is necessary, otherwise onElementEvent is called in window scope
              this.onElementEvent.bind(this).defer();
            }).bind(this));
          }    
          // fall through
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }

Comments and changes to this ticket

  • Scott Hyndman

    Scott Hyndman April 13th, 2008 @ 10:12 PM

    Oh, and if this system doesn't email me when you take a look, would you mind emailing me at scotty.hyndman@gmail.com?

    ALSO,

    If you guys were looking for developers, I'd keen. I know the framework, live and breath JavaScript, and have successfully contributed to OSS in the past.

    Let me know.

    Scott

  • Scott Hyndman

    Scott Hyndman April 13th, 2008 @ 10:20 PM

    Sorry. Fix doesn't seem to cover all cases. I'm working on it.

  • Scott Hyndman

    Scott Hyndman April 13th, 2008 @ 10:50 PM

    Safari dispatches the 'keypress' before changing the value on the select. The below script fixes that, but there is still a problem with Firefox Mac.

      registerCallback: function(element) {
        if (element.type) {
          switch (element.type.toLowerCase()) {
            case 'checkbox':
            case 'radio':
              Event.observe(element, 'click', this.onElementEvent.bind(this));
              break;
            // XXX: [scott] this case is added to fix select-one combos
    		case 'select-one':
              var sz = element.readAttribute('size');
              if(!sz || parseInt(sz) <= 1) { // will match null, 0 or 1 
                Event.observe(element, 'keypress', (function() {
                  // bind() is necessary, otherwise onElementEvent is called in window scope
                  this.onElementEvent.bind(this).defer();
                }).bind(this));
              }    
              // fall through
            default:
              Event.observe(element, 'change', this.onElementEvent.bind(this));
              break;
          }
        }
      }
    

    Alright, here are steps to reproduce. It's a little strange, but I couldn't get anything better that was reproducible.

    With my fix in place, perform the following actions (Mac Firefox):

    1. Drop down the combobox

    2. Type (do not use mouse) 'g'. (selection should change to 'ghi')

    3. Wait for a second, then type 'd'. (selection should change to 'def')

    4. Wait for a second, then type 'g'. (selection should change to 'ghi')

    5. Now click the 'abc' option with the mouse.

    The change event is never received, and the "value is:" text never changes.

    I have found that the event wrapping function created by Event.createWrapper() is never being called on step 5. I have no idea why that might be the case.

    I have however noticed that the select button receives a mousedown event.

    And unless I come up with a clean

  • Andrew Dupont

    Andrew Dupont April 14th, 2008 @ 02:38 AM

    • State changed from “new” to “open”

    We'll take a look at this; thanks. With quirks like these it's no wonder why we have Abstract.TimedObserver.

    The best way to contribute to Prototype right now is to keep submitting bugs, writing patches, helping out in IRC/on the mailing list, and generally doing cool stuff with the library. That's how one accrues Karma Points.

  • John-David Dalton

    John-David Dalton April 15th, 2008 @ 04:10 AM

    related to "[PATCH] Prototype's EventObserver fires only once when observing radio buttons"

    http://dev.rubyonrails.org/ticke...

  • Juriy Zaytsev

    Juriy Zaytsev April 16th, 2008 @ 06:12 AM

    I can't reproduce this no matter what I try : )

    Click, key arrows, etc. all work seamlessly.

    FF2/Mac

  • John-David Dalton

    John-David Dalton April 16th, 2008 @ 07:07 AM

    I could not repeat this either :(. If you don't actually change the value then it won't alert (ex: if the default item is "abc" and you highlight the other items but don't select them and then select "abc" again, then no change has occured and no alert should fire.

    In firefox you can select another item with the arrow keys but the onchange event isn't registered until after the select box loses focus (I don't think that is a bug).

    I tested this on:

    Mac: Safari 2.4, Safari 3.1, Firefox 2.0.0.2, Firefox 2.0.0.12

    Windows: Safari 3.1, Firefox 2.0.0.13

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stric...">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
    <title>Select Test</title>
    <script type="text/javascript" src="prototype.js"></script>
    <script>
      document.observe('dom:loaded', function(){
    	new Form.Element.EventObserver('test1', function(){ alert(this.getValue())});
    	new Form.Element.EventObserver('test2', function(){ alert(this.getValue())});
    	new Form.Element.EventObserver('test3', function(){ alert(this.getValue())});
      });
    </script>
    </head>
    <body>
    
    <form>
    
    <select id="test1">
     <option value="1">abc</option>
     <option value="2">def</option>
     <option value="3">ghi</option>
     <option value="4">jkl</option>
    </select>
    
    <select id="test2" type="select-one">
     <option value="1">abc</option>
     <option value="2">def</option>
     <option value="3">ghi</option>
     <option value="4">jkl</option>
    </select>
    
    <select id="test3" type="select-multiple">
     <option value="1">abc</option>
     <option value="2">def</option>
     <option value="3">ghi</option>
     <option value="4">jkl</option>
    </select>
    
    </form>
    
    </body>
    </html>
    
  • Scott Hyndman

    Scott Hyndman April 16th, 2008 @ 01:54 PM

    I wasn't testing with alerts because they force focus loss, but let me give that a go.

    Did you give my test a try with the instructions (in my second try)?

    I just woke up but I'll be at work in a couple hours. I'll post back then.

  • Scott Hyndman

    Scott Hyndman April 16th, 2008 @ 01:55 PM

    And by second try I mean second comment. haha. Again, just woke up.

  • John-David Dalton

    John-David Dalton April 16th, 2008 @ 03:38 PM

    Yes I did test by your second comments. The alert shouldn't matter because its happening after the "change" you are testing for. I changed the "alert" to "console.log" and viewed the results in Firebug and the Safari javascript console. Still could not reproduce.

  • Scott Hyndman

    Scott Hyndman April 16th, 2008 @ 04:44 PM

    Alright guys, I didn't understand that the "change" event is fired on blur if the select's value is changed through the keyboard.

    Seems a bit odd to me (especially since the select's value actually is changed prior to the blur), but I have verified that you are correct.

  • John-David Dalton

    John-David Dalton April 16th, 2008 @ 07:01 PM

    • Title changed from “Abstract.EventObserver does not invoke callback function when selected value changes on select control” to “[DOC] Using arrow keys, Firefox fires dropdown onchange event after element loses focus, others don't”

    It is a bit strange, Firefox seems to be the oddball here, IE/Opera/Safari will trigger the change before the element looses focus.

    I don't know if this is a bug. I am marking it as a documentation note.

    But feel free to change it if you want.

  • Tobie Langel

    Tobie Langel April 16th, 2008 @ 10:06 PM

    • State changed from “open” to “doc_bug”
    • Title changed from “[DOC] Using arrow keys, Firefox fires dropdown onchange event after element loses focus, others don't” to “Using arrow keys, Firefox fires dropdown onchange event after element loses focus, others don't”
    • Milestone cleared.
  • Tobie Langel

    Tobie Langel April 18th, 2008 @ 01:19 PM

    • State changed from “doc_bug” to “doc”
  • John-David Dalton

    John-David Dalton May 29th, 2008 @ 04:42 AM

    • Assigned user set to “Tobie Langel”
  • Reza S

    Reza S November 12th, 2008 @ 10:37 PM

    • Tag set to form

    For your select box drop down just add the following event: @@@javascript Event.observe(mySelect,'keyup',

            function(event) {
                mySelect.blur();
                mySelect.focus();
            }.bindAsEventListener(this)
    
    

    );

    
    
  • Tobie Langel

    Tobie Langel May 12th, 2009 @ 04:02 PM

    • Assigned user changed from “Tobie Langel” to “T.J. Crowder”

    [responsible:ID#32948 milestone:ID#9627 bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:01 AM

    • Tag changed from form to section:dom

    [not-tagged:"form" tagged:"section:dom" bulk edit command]

  • GitHub Robot

    GitHub Robot August 22nd, 2009 @ 04:45 AM

    • State changed from “doc” to “resolved”

    (from [41d10881600b9f4ae95df722df4efb88d27275ae]) doc: Documented Event.observe and Event.stopObserving, including vagaries about change events across browsers. [#6 state:resolved] http://github.com/sstephenson/prototype/commit/41d10881600b9f4ae95d...

  • Tobie Langel

    Tobie Langel November 29th, 2009 @ 07:18 PM

    • Milestone cleared.
    • Assigned user changed from “T.J. Crowder” to “Samuel Lebeau”
  • Tobie Langel
  • chenlina1

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

Shared Ticket Bins

Attachments

Pages