views:

34

answers:

2

I'm trying to build a form that works in a manner similar to the Google Search page, as well as Gmail and several other pages (including the this page - see the "Tags" input on the Ask Question page). As text is input, a list of options will appear, and the user can use up and down arrows to select the option they want.

The problem I am having is that the up arrow puts the cursor/caret in position 0 of the field, and down puts it at the end. Is there an easy way of keeping it from moving to the beginning/end, or do I need to find the caret position before my function is run, and reposition it to that spot after?

This is the beginning of the function that runs when when text is entered in the input element (onkeyup).

var keycode = checkKeycode (event);   // returns the keycode of the key pressed.
if (keycode == 38) {         // up arrow
    var selection = $(".optionsSelected").attr("id");
    var selId = parseInt(selection.replace('briefOption', ''));
    if (selId != 0) {
        $(".optionsSelected").removeClass("optionsSelected");
        var newSelId = selId - 1;
        $("#briefOption"+newSelId).addClass("optionsSelected");
    }
}
else if (keycode == 40) {     // down arrow
    var selection = $(".optionsSelected").attr("id");
    var selId = parseInt(selection.replace('briefOption', ''));
    if (selId != numAvEmps && numAvEmps != 0) {
        $(".optionsSelected").removeClass("optionsSelected");
        var newSelId = selId + 1;
        $("#briefOption"+newSelId).addClass("optionsSelected");
    }
}
else if (keycode == 27) {    // Escape
    $("#docDropDown").css("display","none");
}
else if (keycode == 9 || keycode == 13) {     //tab or enter
    /* Fill form */
}

Let me know if any more code would be useful. Thanks for the help.

+1  A: 

You'd want to store the caret before and then when you're done doing things, set it back.

Something like this:

HTML body:

<input type="text" id="mytextbox" style="border: 1px solid black" />

Javascript:

function getCaretPosition(ctrl)
{
    var caretPos = 0;    
    // IE
    if (document.selection)
    {
        ctrl.focus ();
        var sel = document.selection.createRange();
        sel.moveStart ('character', -ctrl.value.length);
        caretPos = sel.text.length;
    }
    // Firefox
    else if (ctrl.selectionStart || ctrl.selectionStart == '0')
    {
        caretPos = ctrl.selectionStart;
    }

    return caretPos;
}

function setCaretPosition(ctrl, pos)
{
    if(ctrl.setSelectionRange)
    {
        ctrl.focus();
        ctrl.setSelectionRange(pos,pos);
    }
    else if (ctrl.createTextRange)
    {
        var range = ctrl.createTextRange();
        range.collapse(true);
        range.moveEnd('character', pos);
        range.moveStart('character', pos);
        range.select();
    }
}



$(document).ready(function ()
{

    $("#mytextbox").keydown(function (e)
    {
        // Up
        if(e.which == 38)
        {
            var pos = getCaretPosition(this);

            // Do stuff here that changes the value/caret?

            setCaretPosition(this, pos);
        }
        // Down
        else if(e.which == 40)
        {
            var pos = getCaretPosition(this);

            // Do stuff here that changes the value/caret?

            setCaretPosition(this, pos);
        }

    });

});
TheCloudlessSky
For some reason when I hit the up arrow, the cursor returns to the beginning of the text. It's hard to know what's going wrong, because when I step into the code with firebug or Chrome's tool, the entire browser loses focus, so I can't see where the cursor is and when it moves.
smfoote
@smfoote - Did you try using what I wrote above? Are you setting the cursor *after* you've done something? Could you post the relevant HTML?
TheCloudlessSky
This would be useful if the up and down arrows needed to move the focus elsewhere but, as they won't, saving the location and restoring it seems unnecessary. Preventing the default event is easier.
Rupert
I have found the preventDefault() functionality of jquery, and that works in FF, but not in Chrome, so I'm still a bit stuck.
smfoote
@TheCloudlessSky - Yeah, I did try what you wrote. It didn't work for me. <input type="number" name="docket" id="docket" autocomplete="off" maxlength="9"> is the html of the input element.
smfoote
@smfoote, @Rupert - Yeah I wasn't sure if he wanted the default event to not fire. In that case, yes `preventDefault()` does the trick.
TheCloudlessSky
I suppose I should explain a little bit more - I have to run the search/list creation part of my function onkeyup, because if I run it onkeydown or onkeypress, I miss the last character that was input. So, my solution was to run my up/down navigation function onkeydown, and run the search/list creation onkeyup. I also added the preventDefault() functions in the keydown function just in case. It's working just as I'd hoped.Thanks for all your help.
smfoote
+1  A: 

Just prevent the default action of the event. You can do this by returning false if you're using an event handler property rather than addEventListener/attachEvent, which would be the easiest way:

var input = document.getElementById("your_input");
var suppressKeypress = false;

input.onkeydown = function(evt) {
    evt = evt || window.event;
    var keyCode = evt.keyCode;
    if (keyCode == 38) {
        // Do your stuff here
        suppressKeypress = true; // For Opera; see below
        return false;
    }
    // Other cases here
};

// This bit is for Opera, which only allows you to suppress the default
// action of a keypress in the keypress event (not keydown)
input.onkeypress = function() {
    if (suppressKeypress) {
        suppressKeypress = false;
        return false;
    }
};
Tim Down