简体   繁体   中英

How do I convert Enter to Tab (with focus change) in IE9? It worked in IE8

I have a text input with an onkeydown event handler that converts <Enter> to <Tab> by changing the event's keyCode from 13 to 9.

<input type="text" onkeydown="enterToTab(event);" onchange="changeEvent(this);" 
       name="" value="" />
<!-- Other inputs exist as created via the DOM, but they are not sibling elements. -->

Javascript:

function enterToTab(myEvent) {
    if (myEvent.keyCode == 13) {
        myEvent.keyCode = 9;
    }
}
function changeEvent(myInput) { var test = "hello"; }

In IE8, this caused the onchange event to fire, but that doesn't happen in IE9. Instead, the input field retains focus. How I can I make that happen? (It works in Firefox 3.6 and Chrome 10.0.) This even works in Browser Mode IE9 if I set the Document Mode to "IE8 standards". But it won't work with a Document Mode of "IE9 standards". (My DocType is XHTML 1.0 Transitional.)

Since it works in IE7 & 8, could this be a bug in IE9 that will get fixed?

Please note: I cannot use input.blur() or manually set a new focus , which is advised by all the other solutions that I've read. I've already tried onkeypress and onkeyup with no luck. I need a generic solution that will cause the web app to literally behave as though I'd hit <Tab>. Also, I don't have jQuery, however, Dojo 1.5 is available to me.

Also note: I KNOW this is "wrong" behavior, and that Enter ought to submit the form. However, my client's staff originally come from a green screen environment where Enter moves them between fields. We must retain the same UI. It is what it is.

UPDATE: I found a difference between IE8 & IE9. In IE8, my setting of myEvent.keyCode holds. In IE9, it does NOT. I can update window.event.keyCode , and it will hold, but that won't affect what happens later. Argh... Any ideas?

Looks like IE9 events are immutable. Once they've been fired you can't change the properties on them, just preventDefault() or cancel them. So you best option is to cancel any "enter" events and re-dispatch a new DOM event from the text input.

Example

function enterToTab(event){
    if(event.keyCode == 13){
        var keyEvent = document.createEvent("Event");
        // This is a lovely method signature
        keyEvent.initKeyboardEvent("onkeydown", true, true, window, 9, event.location, "", event.repeat, event.locale);
        event.currentTarget.dispatchEvent(keyEvent);
        // you may want to prevent default here
    }
}

Here's the MSDN documentation around IE9 DOM events:

Event Object - http://msdn.microsoft.com/en-us/library/ms535863(v=vs.85).aspx

createEvent - http://msdn.microsoft.com/en-us/library/ff975304(v=vs.85).aspx

initialize a Keyboard Event - http://msdn.microsoft.com/en-us/library/ff975297(v=vs.85).aspx

The previous IE-version allowed the non standard writable event.keyCode property, IE9 now conforms to the standards.

You may want to consider the functionality you are after: you want to make the enter key behave like the tab key, ie moving the focus to the next (text) input field. There are more ways to do that. One of them is using the tabindex attribute of the text input fields. If you order the fields in your form using this tabindex attribute, the functions I present here may yield the same result as your previous keyCode method. Here are two functions I tested in this jsfiddle . An (text) input field now looks like:

<input type="text" 
       onkeypress="nextOnEnter(this,event);" 
       name="" value="" 
       tabindex="1"/>

the functions to use for tabbing:

function nextOnEnter(obj,e){
    e = e || event;
    // we are storing all input fields with tabindex attribute in 
    // a 'static' field of this function using the external function
    // getTabbableFields
    nextOnEnter.fields = nextOnEnter.fields || getTabbableFields();
    if (e.keyCode === 13) {
        // first, prevent default behavior for enter key (submit)
        if (e.preventDefault){
            e.preventDefault();
        } else if (e.stopPropagation){    
          e.stopPropagation();
        } else {   
          e.returnValue = false;
        }
       // determine current tabindex
       var tabi = parseInt(obj.getAttribute('tabindex'),10);
       // focus to next tabindex in line
       if ( tabi+1 < nextOnEnter.fields.length ){
         nextOnEnter.fields[tabi+1].focus();
        }
    }
}

// returns an array containing all input text/submit fields with a
// tabindex attribute, in the order of the tabindex values
function getTabbableFields(){
    var ret = [],
        inpts = document.getElementsByTagName('input'), 
        i = inpts.length;
    while (i--){
        var tabi = parseInt(inpts[i].getAttribute('tabindex'),10),
            txtType = inpts[i].getAttribute('type');
            // [txtType] could be used to filter out input fields that you
            // don't want to be 'tabbable'
            ret[tabi] = inpts[i];
    }
    return ret;
}

If you don't want to use tabindex and all your input fields are 'tabbable', see this jsfiddle

[ EDIT ] edited functions (see jsfiddles) to make use of event delegation and make it all work in Opera too. And this version imitates shift-TAB too.

Here is a different idea; change the on submit so that it calls a function instead of processing the form. in the function check all the fields to see if they are blank, then focus on the next field that doesn't have a value.
So they type a value into field 1, hit enter, and the function runs. it sees that field 1 is full, but field 2 isn't, so focus on field 2.
Then when all the fields are full, submit the form for processing.
If the form has fields that can be blank, you could use a boolean array that would keep track of which fields received focus using the onfocus() event.

Just an outside the box idea.

The code above causes problems. Here's some code that will help you. Works on IE9, FF5 etc.

function getNextElement(field) {
    var form = field.form;
    for ( var e = 0; e < form.elements.length; e++) {
        if (field == form.elements[e]) {
            break;
        }
    }
    return form.elements[++e % form.elements.length];
}

function tabOnEnter(field, evt) {
if (evt.keyCode === 13) {
        if (evt.preventDefault) {
            evt.preventDefault();
        } else if (evt.stopPropagation) {
            evt.stopPropagation();
        } else {
            evt.returnValue = false;
        }
        getNextElement(field).focus();
        return false;
    } else {
        return true;
    }
}

And then you should just create your input texts or whatever

<input type="text" id="1" onkeydown="return tabOnEnter(this,event)"/>
<input type="text" id="2" onkeydown="return tabOnEnter(this,event)"/>
<input type="text" id="3" onkeydown="return tabOnEnter(this,event)"/>
<input type="text" id="4" onkeydown="return tabOnEnter(this,event)"/>

A <button> element on a page will cause this problem.

In IE9 a <button> element takes the focus when Enter is pressed. Any submit or reset button will cause the problem too. If you are not using submit/reset then you can fix this by changing all buttons to <input type="button"> or by setting the button's type attribute to button. ie

<button type="button">Click me!</button>

Alternatively as per KooiInc's answer, you can edit your javascript to use event.preventDefault(); to prevent the Enter key acting this way, and explicitly call focus() on the next element in the tab order.

Here is some test code I wrote that demonstrates the problem with the button element (note the blue focus ring on button3 in IE9):

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>IE problem with Enter key and &lt;button&gt; elements</title>
</head>

<body>
    <script>
        function press(event) {
            if (event.keyCode == 13) {
                document.getElementById('input2').focus();
                // In IE9 the focus shifts to the <button> unless we call preventDefault(). Uncomment following line for IE9 fix. Alternatively set type="button" on all button elements and anything else that is a submit or reset too!.
                // event.preventDefault && event.preventDefault();
            }
        }
    </script>
    <input id="input1" type="text" onkeypress="press(event)" value="input1. Press enter here." /><br />
    <input id="input2" type="text" value="input2. Press enter here." /><br />
    <input  id="button1" type="button" value='I am an <input type="button">' /><br />
    <button id="button2" type="button">I am a &lt;button type="button"&gt;</button><br />
    <button id="button3">I am a &lt;button&gt;. I get focus when enter key pressed in IE9 - wooot!</button><span>As per Microsoft docs on <a target="_tab" href="http://msdn.microsoft.com/en-us/library/ms534696%28v=vs.85%29.aspx">BUTTON.type</a> it is because type defaults to submit.</span>
</body>
</html>

Mike Fdz's code is superb. In order to skip over hidden fields, you may want to change the line

return form.elements[++e % form.elements.length]; 

to this:

e++;
while (form.elements[e % form.elements.length].type == "hidden") {
    e++;
}
return form.elements[e % form.elements.length];

Use onpaste along with onkeypress like

Consider you have wrriten a javascript function which checks the text lenght so we will need to validate it on key press like as below

<asp:TextBox ID="txtInputText" runat="server" Text="Please enter some text" onpaste="return textboxMultilineMaxNumber(this,1000);" onkeypress="return textboxMultilineMaxNumber(this,1000);"></asp:TextBox>

onkeypress will work in both FF and IE

but if you try to do ctr+V in textbox then onpaste will handle in IE in FF onkeypress takes care of it

To prevent a "submit event" triggered by Enter-Keyboard in your Form in IE9, retire any button inside the form area. Place him (button) in outside of form's area.

 function enterAsTab() { var keyPressed = event.keyCode; // get the Key that is pressed if (keyPressed == 13) { //case the KeyPressed is the [Enter] var inputs = $('input'); // storage a array of Inputs var a = inputs.index(document.activeElement); //get the Index of Active Element Input inside the Inputs(array) if (inputs[a + 1] !== null) { // case the next index of array is not null var nextBox = inputs[a + 1]; nextBox.focus(); // Focus the next input element. Make him an Active Element event.preventDefault(); } return false; } else {return keyPressed;} } 
 <HTML> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body onKeyPress="return enterAsTab();"> <input type='text' /> <input type='text' /> <input type='text' /> <input type='text' /> <input type='text' /> </body> </HTML> 

This is what I have done with what I found over the internet :

function stopRKey(evt) 
{ 
  var evt = (evt) ? evt : ((event) ? event : null); 
  var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null); 
  if ((evt.keyCode == 13) && ((node.type=="text") || (node.type=="radio")))  
  { 
      getNextElement(node).focus();  
      return false;   
    } 
} 

function getNextElement(field) 
{
    var form = field.form;
    for ( var e = 0; e < form.elements.length; e++) {
        if (field == form.elements[e]) {
            break;
        }
    }
    e++;
    while (form.elements[e % form.elements.length].type == "hidden") 
    {
        e++;
    }
    return form.elements[e % form.elements.length];;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM