views:

356

answers:

3

I have a form with some select elements. One of them is configured so that if the user changes the value, the next input may get enabled or disabled, depending on the value. When changing the value with the mouse, everything works fine. However, when using the keyboard, strange things happen. It acts differently from one browser to another.

In Firefox, if I change the value to enable the next input, then press the tab key, the focus skips the input that was just enabled. I can focus it by pressing shift+tab, but I think that may be annoying and confusing to users.

In Chrome, if I change the value to enable the next input, then press tab, the focus jumps like in Firefox. If I change the value to disable the next input, then press tab, the next input gets focused despite being disabled. This is strange, but not a big deal because the user can press tab again and focus the input after it.

In Internet Explorer, something very strange happens: everything works fine! If I change the value to enable the next input, then press tab, the next input gets focused. If I change the value to disable the next input, then press tab, the focus skips the disabled input. It works in IE 6, 7, and 8.

I am doing the enabling and disabling with jQuery. I haven't had a chance to test it with plain Javascript so far.

You can test this issue with the following page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html><head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>select focus test</title>
</head>
<body>
<select id="enabler">
    <option value="0" selected>Disabled
    <option value="1">Enabled
</select>
<select id="target" disabled>
    <option value="a">a
    <option value="b">b
</select>
<select id="next">
    <option value="x">x
    <option value="y">y
</select>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$("#enabler").change(function() {
    $enabler = $(this);
    $("#target").attr("disabled", $enabler.val() == "0");
});
</script>
</body></html>

If you change the value of the first dropdown, then press tab, you can see the behavior.

Here is my question: Is there any way to make the form act in all browsers like it does in IE?

+1  A: 

I just tried your code, and managed to duplicate what you described. I tried to produce the desired behaviour by:

  • explicitly setting tabindexes for the drop-downs. (would be a good idea anyway)
  • closing your option tags (you really should be doing this)
  • enclosing your jQuery within a $(document).ready block. (you really should be doing this too)

None of the above did the trick, but here's a simple workaround to automatically focus the target element (tested in FF/Safari):

   $(document).ready(function() {
         $("#enabler").change(function() {
            $enabler = $(this);
            $("#target").attr("disabled", $enabler.val() == "0")
                        .focus();
        });
   });
karim79
This code sample is a simple test case to show the problem without confusing people with too many irrelevant details. You were right that the tabindexes, closing tags, and $(document).ready did nothing to fix the problem.I tried your solution and it seemed to solve the problem, but now when I change the value with the mouse, the next input gets focused. Can I avoid this?I am trying to do something more general. I have a bunch of inputs in my form, some with more complex handlers. Is there any way to come up with a generic handler so when I push tab on any select, the next one gets focused?
mikez302
+1  A: 

My guess is that your problem is that due to differences in the sequence of events between browsers, the change event is getting fired after the focus has moved.

There are 4 events fired: keydown, keyup, keypress, and, change.

Let's say that the browser moves the focus when keypress occurs. Then it matters what the sequence looks like:

  1. keydown
  2. keyup
  3. change [element is enabled/disabled]
  4. keypress [focus moves]

Would work just fine. But if the sequence looks like this:

  1. keydown
  2. keyup
  3. keypress [focus moves]
  4. change [element is enabled/disabled]

Then the change event is occurring to late for the focus to take the state of the element into account.

You can log out the events to verify this:

$("#enabler").bind('change click keypress keydown keypress blur', function(e) {
   console.log( e.type );
});

The simplest solution would be to add the enable/disable handler to more events:

$("#enabler").bind('change click keypress', function() {
    $enabler = $(this);
    $("#target").attr("disabled", $enabler.val() == "0");
});
Borgar
I tried your solution and it seemed to work well. I still had problems in Chrome, but I fixed them with a minor modification: I used "keydown" instead of "keypress".
mikez302
A: 

I figured it out. Here is how I did it:

$("#enabler").bind("change click keydown", function() {
    $enabler = $(this);
    $("#target").attr("disabled", $enabler.val() == "0");
});

This is Borgar's idea with a minor modification.

mikez302