Jump to content

Search Suggestions Menu with keyboard navigation


Fmdpa

Recommended Posts

see post #7 for the filesSome of you may recall when I was creating a search suggestions menu. It was quite basic, and now I'm extending its functionality. Mainly, I'm trying to allow the keyboard to control which <li> element is selected. So far, I've detected two problems:1. The hover event is not properly binding to the individual list elements in the for loop. When there should be a class applied to the element on hover, nothing happens. No errors, either. 2. When the "up" or "down" keyboard arrows are hit, the "active_li" class is only applied to the element as long as the event is active. i.e, if I use the keypress event, the classname is only applied to the element as long as the key is pressed. Why isn't the className sticking to the element until it is removed?Any other tips or notices would be appreciated.

$('#search_box').blur(function() {   $('ul#search_suggestions').fadeOut(300);});searchSuggestionsNav = function() {	currentIndex = 0;	input = $('#search_box');	input.suggestionsList = $('ul#search_suggestions');		input.active = 'active_li';	$('#search_box').keyup(function() {	   var query_val = $('#search_box').val();	   input.items = document.getElementById('search_suggestions').getElementsByTagName('li');	   $.post(			'/autocomplete.php', {				'query_val' : query_val			},			function(text) {				var search_suggestions = $('ul#search_suggestions');				if (!text) {					search_suggestions.fadeOut("normal");				}				else {				search_suggestions.html(text);				search_suggestions.fadeIn(500);				search_suggestions.click(function() {						txt = $(this).children('li').html();						$('input#search_box').val(txt);						$('#search_form').submit();					});				}			});			for ( j = 0; j < input.items.length; j++ ) {			 //problem #1...				$(input.items[j]).hover(function() {					currentIndex = j + 1;					$(input.items[j]).addClass(input.active);				}, function() {					$(input.items[j]).removeClass(input.active);				});			}		});		$('#search_box').keypress(function(e) {									   //problem #2...			switch(getEventCode(e)) {				case 13 : //prevent form submission through the enter button					$('#search_box').val($(input.items[currentIndex-1]).html());					$('#search_suggestions').fadeOut();					return false;					break;				case 38 :					go("up");					break;				case 40 :					go("down");					break;				case 27 :					$('ul#search_suggestions').fadeOut(300);					break;				default :					//go("nowhere")					break;			}	});	go = function(where) {		last = currentIndex;		currentIndex += (where == "down") ? 1 : -1;		if (currentIndex < 1) currentIndex = input.items.length;		if (currentIndex > input.items.length) currentIndex = 1;		selectItem(currentIndex, last);	}	selectItem = function(index, lastIndex) {		for ( i =1; i <= input.items.length; i++ ) {			if (i == index) {				thisElem = input.items[i-1];				$(thisElem).addClass(input.active);			}			if (i == lastIndex) {				thisElem = input.items[i-1];				$(thisElem).removeClass(input.active);			}		}	}	submitForm = function() {		value = input.items[currentIndex-1].html();		$('input#search_box').val(value);		//$('#search_form').submit();	}	reset = function() {		currentIndex = 0;	}}

Link to comment
Share on other sites

when is this function running? after the document has loaded? Are you getting anything returned when this line runs?

input.items = document.getElementById('search_suggestions').getElementsByTagName('li');

Link to comment
Share on other sites

Why are you looping over all elements in selectItem? Why not just access input.items[index] and input.items[lastIndex] directly? You may want to print those values to make sure that it's getting called with the correct arguments.

Link to comment
Share on other sites

Thanks for showing me that. I'm not sure why I did that. Maybe it is because I originally was using pure Javascript.

selectItem = function(index, previousIndex) {		$(input.items[index-1]).addClass(input.active);		$(input.items[previousIndex-1]).removeClass(input.active);	}

However, it still does the same thing. The correct items are being selected (and the selection loops around the list if you hold on arrow down). I just can't figure out why the className is only applied to the element as long as the event is active.

Link to comment
Share on other sites

It might be part of the magic of jQuery, I don't see anywhere where you're explicitly telling it to remove the class on key up. The only place you're telling it to remove the class is on key down, so I would add some debugging statements there to see if that function gets called again when you release the key.

Link to comment
Share on other sites

I think it was occurring when I was using pure JS (when I began the script).Here's a working example for you to try. Of course the real example has much more to the backend, but this should contain the relevant stuff. the html file (make sure to load jQuery)

<!DOCTYPE HTML><html>  <head>	<title></title>	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">	<style type="text/css">		.active_li { font-weight:bold; }	</style>  </head>  <body>	<form action="/search.php" action="get" id="search_form">		<input type="text" id="search_box" accesskey="4" name="query" autocomplete="off" />		<button type="submit" id="searchFormSubmit">Go!</button>		<ul id="search_suggestions"></ul>	</form>	<script src="/scripts/jquery.js"></script>	<script>		$('#search_box').blur(function() {		   $('ul#search_suggestions').fadeOut(300);		});		searchSuggestionsNav = function() {			currentIndex = 0;			input = $('#search_box');			input.suggestionsList = $('ul#search_suggestions');			input.active = 'active_li';			$('#search_box').keyup(function() {			   var query_val = $('#search_box').val();			   input.items = document.getElementById('search_suggestions').getElementsByTagName('li');			   $.post(					'/test_menu.php', {						'query_val' : query_val					},					function(text) {						var search_suggestions = $('ul#search_suggestions');						if (!text) {							search_suggestions.fadeOut("normal");						}						else {						search_suggestions.html(text);						search_suggestions.fadeIn(500);						search_suggestions.click(function() {								txt = $(this).children('li').html();								$('input#search_box').val(txt);								$('#search_form').submit();							});						}					});					for ( j = 0; j < input.items.length; j++ ) {						$(input.items[j]).hover(function() {							currentIndex = j + 1;							$(input.items[j]).addClass(input.active);						}, function() {							$(input.items[j]).removeClass(input.active);						});					}				});				$('#search_box').keypress(function(e) {					switch(getEventCode(e)) {						case 13 : //prevent form submission through the enter button							if ($('ul#search_suggestions').children('li').length <= 1) {								return true;							} else {								$('#search_box').val($(input.items[currentIndex-1]).html());								$('#search_suggestions').fadeOut();								return false;							}							break;						case 38 :							go("up");							break;						case 40 :							go("down");							break;						case 27 :							$('ul#search_suggestions').fadeOut(300);							break;						default :							//go("nowhere")							break;					}			});			go = function(where) {				previous = currentIndex;				currentIndex += (where == "down") ? 1 : -1;				if (currentIndex < 1) currentIndex = input.items.length;				if (currentIndex > input.items.length) currentIndex = 1;				selectItem(currentIndex, previous);			}			selectItem = function(index, previousIndex) {				$(input.items[index-1]).addClass(input.active);				$(input.items[previousIndex -1]).removeClass(input.active);			}			submitForm = function() {				value = input.items[currentIndex-1].html();				$('input#search_box').val(value);			}			reset = function() {				currentIndex = 0;			}		}		$(document).ready(searchSuggestionsNav);		getEventCode = function(evt) {		   code = null;		   if (!evt) evt = window.event;		   code = evt.keyCode;		   return code;		}	</script>  </body></html>

test_menu.php

<?php$suggestions = array('suggestion1', 'suggestion2', 'suggestion3');foreach ($suggestions as $val) {	echo '<li>' . $val . '</li>';}

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...