Reputation: 3184
I have a search box which has an auto-complete feature that I've been building. I'm having a couple issues.
Two things:
When arrowing up and down through the list of auto-completed/search terms, it's including those which were hidden by the filter. How can I make sure only the visible list items can be traversed?
When I hit enter to select one of the items from the list, the dropdown is still there because it is matching the word in the search box.
Some code:
$(document).ready(function() {
$("#dropdown").hide();
$("input").keyup(function() {
if (this.value.length) {
var that = this;
$("#dropdown li").hide().filter(function() {
return $(this).html().toLowerCase().indexOf(that.value.toLowerCase()) !== -1;
}).show();
$("#dropdown").show();
}
else {
$("#dropdown").hide();
}
});
$('li').click(function() {
$('#search').val($(this).text());
$("#dropdown").hide();
});
var li = $('li');
var liSelected;
$('input').keydown(function(e) {
if(e.which === 40) {
if(liSelected) {
liSelected.removeClass('selected');
next = liSelected.next();
if(next.length > 0) {
liSelected = next.addClass('selected');
$('#search').val(liSelected.text());
}
else {
liSelected = li.eq(0).addClass('selected');
}
}
else {
liSelected = li.eq(0).addClass('selected');
}
}
else if(e.which === 38) {
if(liSelected) {
liSelected.removeClass('selected');
next = liSelected.prev();
if(next.length > 0) {
liSelected = next.addClass('selected');
}
else {
liSelected = li.last().addClass('selected');
}
}
else {
liSelected = li.last().addClass('selected');
}
}
else if(e.which === 13) {
$('#search').val(liSelected.text());
$("#dropdown").hide()
$('#search').blur();
}
});
});
Upvotes: 0
Views: 104
Reputation: 12294
The point is you are showing only elements out of a .filter() call, but the elements are still present in the same list. You need to create another list, hidden, where you will put the hidden elements. Each time the user update the search field, you have to check each element in both lists: the one who needs to be visible will go in the visible list, the ones you don't want to show will go in the hidden list.
Here's an example
$("input").keyup(function(e) {
if (this.value.length) {
var that = this;
$("#dropdown li").each(function() {
if ( $(this).html().toLowerCase().indexOf(that.value.toLowerCase()) == -1 )
$(this).appendTo($hidden);
});
$('#hidden li').each(function() {
if ( $(this).html().toLowerCase().indexOf(that.value.toLowerCase()) !== -1 )
$(this).appendTo('#list');
});
$("#dropdown").show();
}
else {
$("#dropdown").hide();
}
if ( e.which !== 40 && e.which !== 38 )
{
$('#dropdown li,#hidden li').each( function() {
$(this).removeClass( 'selected' );
});
liSelected = null;
}
});
You now have two lists to check every time. Caching the results of the li's is not possible now like you were doing before, as their number and position is constantly changing.
Here I changed your code to show you what I mean, there may be some bugs but you should get the point.
Upvotes: 1