Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture keypress to filter elements

I'm creating a <select> replacement using jQuery to replace it with divs and links.

Now I want to filter it when I start to type something with the new select open.

Like Google Translate does on the language selector.

Do you have any advice how do i proceed?

I started something with:

$(document).bind('keypress', function(event) {
   //...
});

But I capture only single keys, not the whole typed string.


Important:

  • I don't have an <input /> to detect the keypress or keyup events on it
  • I prefer not to create this <input /> since I want to use only <div>'s and <a>'s on the "new select"
  • Lately I'll need to navigate on the open select with arrow keys + enter to select the option with my keyboard
like image 616
Thiago Belem Avatar asked May 09 '11 15:05

Thiago Belem


People also ask

Is Onkeypress deprecated?

Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes.

Which event captures a keypress in Javascript?

The onkeypress event occurs when the user presses a key (on the keyboard). Tip: The order of events related to the onkeypress event: onkeydown. onkeypress.

What is keypress function?

The keypress() method triggers the keypress event, or attaches a function to run when a keypress event occurs. The keypress event is similar to the keydown event. The event occurs when a button is pressed down. However, the keypress event is not fired for all keys (e.g. ALT, CTRL, SHIFT, ESC).


3 Answers

You could achieve this by 'listening' about what is pressed on the window, and then detecting the particular letter/string pressed, search through items list and if you find it change its css properties or add a new 'selected' class i.e. (demo => http://jsfiddle.net/steweb/mC6tn/ ..try pressing whatever :) and added after something found press left or right btns, or enter) :

JS: (supposing that each element you want to find something into and select it has class 'elem')

var whatYouAreSearching = $('<div class="searching-string"></div>'); //just to see what string you're typing
$(document.body).append(whatYouAreSearching);

function search(what){
    what = what.toLowerCase();
    $('.elem').removeClass('selected'); //reset everything
    $.each($('.elem'),function(index,el){
        if($(el).html().toLowerCase().indexOf(what) > -1){
            $(el).addClass('selected');
            return false; //found, 'break' the each loop
        }
    });
}

var letterPressed = [];
var timeOutResetLetters = null;

$(window).keypress(function(e) {
    clearTimeout(timeOutResetLetters); //clear timeout, important!
    timeOutResetLetters = setTimeout(function(){ //if 500 ms of inactivity, reset array of letters pressed and searching string
        letterPressed = []; 
        whatYouAreSearching.html('');
    },500);
    letterPressed.push(String.fromCharCode(e.keyCode)); //look at the comment, thanks Niclas Sahlin 
    whatYouAreSearching.html(letterPressed.join('')); //show string
    search(letterPressed.join('')); //and search string by 'joining' characters array
});

EDIT added left/right/enter keys handling

$(window).keydown(function(e){ //left right handling
    var currSelected = $('.elem.selected');

    if(e.keyCode == "37"){ //left, select prev
        if(currSelected.prev() && currSelected.prev().hasClass('elem')){
            currSelected.prev().addClass('selected');
            currSelected.removeClass('selected');   
        }
    }else if(e.keyCode == "39"){ //right, select next
        if(currSelected.next() && currSelected.next().hasClass('elem')){
            currSelected.next().addClass('selected');
            currSelected.removeClass('selected');   
        }
    }else if(e.keyCode == "13"){ //enter
       $('.entered').remove();
       $(document.body).append(currSelected.clone().addClass('entered'));
    }
});
like image 77
stecb Avatar answered Oct 23 '22 21:10

stecb


You can try using jQuery UI's autocomplete

like image 44
Naftali Avatar answered Oct 23 '22 20:10

Naftali


How to do what you asked

Each time the keypress event is triggered on the document, keep a record of the character that was typed, either in a variable (accessible from the global scope or in a closure) or in an element on the page (you may choose to use display: hidden; if you don't want this to be visible to the user).

Then, do a pass over the elements in your dropdown and hide those that don't contain/start with the string you've built from individual keystrokes.

What's actually recommended

Use an input element to contain the user's typed keystrokes, and let the user see the element.

Why?

Because it's an interaction behavior users are already familiar with. If you don't use an input element, you open several new questions that are already solved with an input element:

  1. How does the user know that they can type to filter the list? Input elements are a clear declaration to the user: "You should type here!"
  2. How does the user know what string is going to be filtered on when they press more than one key? When I quickly type 'hu' in that Google Translate interface, 'Hungarian' is selected, as I would expect. However, what happens when I type it slowly? If it's slow enough, 'Hatian Creole' is selected, and then 'Ukranian'.
  3. What if I mistype something and want to start over? Is there a button to press to clear it out? How long do I need to wait for the filter to clear on its own?

You could certainly create a new interface element that solves all of these problems, and if that's your goal, go for it, but there are preexisting standards for these sorts of things.

For one, that previously-mentioned autocomplete widget is really handy, and really flexible.

like image 1
quasistoic Avatar answered Oct 23 '22 20:10

quasistoic