views:

993

answers:

4

I have some textboxes on a page and I want to click a link when the user presses enter in any of them.

I can easily trap the enter button using javascript (by looking for 13 in event.keyCode and event.which), but I hit an issue when the browser's autocomplete feature kicks in and suggests what the user might want to type. We're finding the users often press enter to accept the browser's suggestion, rather than tab. This confuses the users as the link is clicked immediately, whereas they still intended to enter text into some of the other fields.

I know it would be better to use a form and a submit button here, but for various reasons that's not practical.

I'm using jQuery, so feel free to offer jQuery solutions.

+3  A: 

Try setting the autocomplete off on your check box, though this is not standard for all browser but it works on the common browsers.

<input type="text" autocomplete="off" />
jerjer
It would be a shame to lose the autocomplete function altogether.
teedyay
A: 

I'm not sure if you are trapping key presses on the window, or on specific DOM elements. You should do the latter (e.g. on the form element), then in your event handler, look into the event object to determine which DOM element was the origin of the event. If this was a text field with autocomplete, then return false;.

Take a look at jQuery's .keypress() event handler, and the event.target property of the event object.

Premasagar
Having found the text input that had the focus when the user pressed enter, how do I determine whether or not the browser's autocomplete was being used at the time?
teedyay
I'm guessing that it isn't an option for you to treat any text fields that is relevant for the auto-complete as not being relevant for submitting the form?If not, then you could combine this approach with @tuanvt's suggestion of trapping the order of keypresses, to determine when a "down" arrow (potentially followed by an "up" arrow) was pressed.
Premasagar
Either way, targetting the form and not the window would be a good idea, since this reduces the chance of conflicts in later development.
Premasagar
Hi, whoever down-voted this suggestion. Care to share why you found it unhelpful?
Premasagar
I down-voted.I want to know how to detect if the user is in the browser's autocomplete suggestion at the point they press enter: your answer gives me no help in how to do this.Your answer tells me how to find which element the user is in when they press enter, then says "If this was a text field with autocomplete...", but doesn't tell me how to find this information, which is what my question is all about.
teedyay
OK, thanks for responding. I was assuming that you knew which of your form fields was ripe for autocompletion. Cool, cool.
Premasagar
+3  A: 

User always have to press the down key if they choose to select one of the auto complete text right, why not set a variable to something when they press the down key, and then if they do the enter press afterwards you check the variable. You should not do the link click function if the variable is set, otherwise do it as normal.

tuanvt
Wow - this is pretty Heath Robinson, but I like it! I guess I'll have to track other keystrokes (up/ down/ page up/ page down as they navigate the list; anything else to return to typing), and set/ reset the flag appropriately. I feel a jQuery extension coming on...
teedyay
let me know when the plugin comes out please, it sounds like a whole lot of key press tracking to do:D, gud luck
tuanvt
This is a good idea. Remember that the user might press the "up" key in between pressing the "down" and "enter" keys.
Premasagar
@tuanvt - it wasn't too bad, as it turns out! I've put the code in another answer to this question, but I'll leave yours as the accepted one as you did the hard work really. Hope you find it useful!
teedyay
+1  A: 

Using tuanvt's idea in the accepted answer, I wrote a jQuery plugin that does the job.

I track when the user presses the up, down, page-up and page-down keys to tell when they're in the autocomplete box. All other keys imply they've left it.

I ensure that we only apply these rules to textboxes: all other input elements behave normally.

Opera already does a pretty good job of what I was trying to achieve, so I don't enforce my rules in that browser - otherwise the user would have to press enter twice.

Tested in IE6, IE7, IE8, Firefox 3.5.5, Google Chrome 3.0, Safari 4.0.4, Opera 10.00.

It's available on jquery.com as the SafeEnter plugin. For your convenience, the code for release 1.0 is as follows:

// jQuery plugin: SafeEnter 1.0
// http://plugins.jquery.com/project/SafeEnter
// by teedyay
//
// Fires an event when the user presses Enter, but not whilst they're in the browser's autocomplete suggestions

//codesnippet:2e23681e-c3a9-46ce-be93-48cc3aba2c73
(function($)
{
    $.fn.listenForEnter = function()
    {
        return this.each(function()
        {
            $(this).focus(function()
            {
                $(this).data('safeEnter_InAutocomplete', false);
            });
            $(this).keypress(function(e)
            {
                var key = (e.keyCode ? e.keyCode : e.which);
                switch (key)
                {
                    case 13:
                        // Fire the event if:
                        //   - we're not currently in the browser's Autocomplete, or
                        //   - this isn't a textbox, or
                        //   - this is Opera (which provides its own protection)
                        if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input[type=text]') || $.browser.opera)
                        {
                            $(this).trigger('pressedEnter', e);
                        }
                        $(this).data('safeEnter_InAutocomplete', false);
                        break;

                    case 40:
                    case 38:
                    case 34:
                    case 33:
                        // down=40,up=38,pgdn=34,pgup=33
                        $(this).data('safeEnter_InAutocomplete', true);
                        break;

                    default:
                        $(this).data('safeEnter_InAutocomplete', false);
                        break;
                }
            });
        });
    };

    $.fn.clickOnEnter = function(target)
    {
        return this.each(function()
        {
            $(this)
                .listenForEnter()
                .bind('pressedEnter', function()
                {
                    $(target).click();
                });
        });
    };
})(jQuery);
teedyay