J
Joel Byrd
I'm having a little problem with using type-ahead functionality for an
auto-suggest box. Sometimes, when I start to type something and the
type-ahead shows up, the AJAX will send a request query using the value
that *includes* the type-ahead value. In other words, say that I type
in "ja" and the first listing that comes up is "(e-mail address removed)". The
AJAX part is supposed to send "ja" as one of the query string variables
when calling the remote file (using the GET method); this way, the
response from the remote script should be all the listings that start
with "ja". BUT, for some reason, sometimes the query string that is
sent *includes* the type-ahead value, so instead of sending just "ja",
it will send "(e-mail address removed)", and consequently, narrow the search down
to this one listing. I'm assuming this is some sort of synchronization
problem (XmlHttpRequest being asynchronous), but I haven't been able to
figure it out.
Here is the code that executes for the keyup event of a legitimate key
(excluding keys like Shift, Home, etc.):
[------------------------------------------------------------------------
function doSuggest() { getSuggest(db_table_name, db_column_name,
element(input_box_id).value, max_listings); }
timeoutID = window.setTimeout(doSuggest, 250);
--------------------------------------------------------------------------]
And here's the getSuggest function:
[--------------------------------------------------------------------------
function getSuggest(db_table_name, db_column_name, db_search,
max_listings) {
if (!isWorking && http) {
var randomNumber = Math.floor(Math.random() * 9999999);
var url = "../get_suggest.php" +
"?r=" + randomNumber+
"&db_table_name=" + db_table_name +
"&db_column_name=" + db_column_name +
"&db_search=" + db_search +
"&max_listings=" + max_listings;
http.onreadystatechange = handleHttpResponseXML;
http.open("GET", url, true);
//By the way, I've tried swapping the
above 2 lines, but this doesn't seem to make a difference.
isWorking = true;
http.send(null);
}
}//end function getSuggest
--------------------------------------------------------------------------]
Finally, here's the handleHttpResponseXML code:
function handleHttpResponseXML() {
if (http.readyState == 4) {
if (http.status != 200) {
alert("ERROR ON REMOTE SCRIPT! " + http.status);
return false;
}
if (http.responseText.indexOf('invalid') == -1 && http.status
== 200) {
var xmlDocument = http.responseXML;
var num_rows =
xmlDocument.getElementsByTagName('num_rows')[0].firstChild.data;
if(num_rows < 1) {
hide('suggest_box');
} else {//(num_rows >= 1)
var listings =
xmlDocument.getElementsByTagName('output')[0].firstChild.data;
num_listings = num_rows;
document.getElementById('suggest_box').innerHTML = listings;
show('suggest_box', 'inline');
//Reset listing_number back to 1 and highlight it.
listing_number = 1;
highlight('listing1');
//----------- TYPE-AHEAD ------------//
//If user pressed backspace or delete, don't do type-ahead.
if (key == BACKSPACE || key == DELETE) {
//Ignore.
} else {
//Show the first listing (which is the closest match) in the
//textbox, highlighting the part the user has not typed.
//First, get length of the text currently in textbox.
var charLength =
document.getElementById(input_box_id).value.length;
//Next, show the listing in the search box.
document.getElementById(input_box_id).value =
document.getElementById('listing1').innerHTML;
//Finally, highlight everything in the search box
//after what the user had originally typed:
highlightRange(input_box_id, charLength);
}//end type-ahead block
}//end else (num_rows >= 1)
isWorking = false;
}
}
}//end function handleHttpResponseXML
I guess I need to include the highlightRange function, too:
[-----------------------------------------------------------------------
function highlightRange(elem, start, end) {
var textbox = document.getElementById(elem);
charLength = textbox.value.length;
switch (arguments.length) {
case 1:
start = 0;
end = charLength;
break;
case 2:
end = charLength;
break;
}//end switch
if (textbox.createTextRange) {
var range = textbox.createTextRange()
range.moveStart("character", start);
range.moveEnd("character", end);
range.select();
} else if (textbox.setSelectionRange) {
textbox.setSelectionRange(start, end);
}
}//end function hightlightRange
------------------------------------------------------------------------]
Alright, so again, I know it's probably a synchronization problem.
I've tried using setTimeout, but this isn't going to solve the problem.
Also, I've found out exactly when the problem occurs. Using the same
example, let's say that "(e-mail address removed)" is the first listing that comes
up for "ja". And let's say that I'm looking for something starting
with "jas". Now, the problem occurs exactly in the following timing: I
type "ja" quickly, wait a split second and then *right before*
"(e-mail address removed)" shows up, I type in an "s" - but the result from typing
the "ja" ("(e-mail address removed)") shows up and overrides the "s" I just typed
in. Any ideas on how I can fix this problem (or synchronize the AJAX
properly)?
auto-suggest box. Sometimes, when I start to type something and the
type-ahead shows up, the AJAX will send a request query using the value
that *includes* the type-ahead value. In other words, say that I type
in "ja" and the first listing that comes up is "(e-mail address removed)". The
AJAX part is supposed to send "ja" as one of the query string variables
when calling the remote file (using the GET method); this way, the
response from the remote script should be all the listings that start
with "ja". BUT, for some reason, sometimes the query string that is
sent *includes* the type-ahead value, so instead of sending just "ja",
it will send "(e-mail address removed)", and consequently, narrow the search down
to this one listing. I'm assuming this is some sort of synchronization
problem (XmlHttpRequest being asynchronous), but I haven't been able to
figure it out.
Here is the code that executes for the keyup event of a legitimate key
(excluding keys like Shift, Home, etc.):
[------------------------------------------------------------------------
function doSuggest() { getSuggest(db_table_name, db_column_name,
element(input_box_id).value, max_listings); }
timeoutID = window.setTimeout(doSuggest, 250);
--------------------------------------------------------------------------]
And here's the getSuggest function:
[--------------------------------------------------------------------------
function getSuggest(db_table_name, db_column_name, db_search,
max_listings) {
if (!isWorking && http) {
var randomNumber = Math.floor(Math.random() * 9999999);
var url = "../get_suggest.php" +
"?r=" + randomNumber+
"&db_table_name=" + db_table_name +
"&db_column_name=" + db_column_name +
"&db_search=" + db_search +
"&max_listings=" + max_listings;
http.onreadystatechange = handleHttpResponseXML;
http.open("GET", url, true);
//By the way, I've tried swapping the
above 2 lines, but this doesn't seem to make a difference.
isWorking = true;
http.send(null);
}
}//end function getSuggest
--------------------------------------------------------------------------]
Finally, here's the handleHttpResponseXML code:
function handleHttpResponseXML() {
if (http.readyState == 4) {
if (http.status != 200) {
alert("ERROR ON REMOTE SCRIPT! " + http.status);
return false;
}
if (http.responseText.indexOf('invalid') == -1 && http.status
== 200) {
var xmlDocument = http.responseXML;
var num_rows =
xmlDocument.getElementsByTagName('num_rows')[0].firstChild.data;
if(num_rows < 1) {
hide('suggest_box');
} else {//(num_rows >= 1)
var listings =
xmlDocument.getElementsByTagName('output')[0].firstChild.data;
num_listings = num_rows;
document.getElementById('suggest_box').innerHTML = listings;
show('suggest_box', 'inline');
//Reset listing_number back to 1 and highlight it.
listing_number = 1;
highlight('listing1');
//----------- TYPE-AHEAD ------------//
//If user pressed backspace or delete, don't do type-ahead.
if (key == BACKSPACE || key == DELETE) {
//Ignore.
} else {
//Show the first listing (which is the closest match) in the
//textbox, highlighting the part the user has not typed.
//First, get length of the text currently in textbox.
var charLength =
document.getElementById(input_box_id).value.length;
//Next, show the listing in the search box.
document.getElementById(input_box_id).value =
document.getElementById('listing1').innerHTML;
//Finally, highlight everything in the search box
//after what the user had originally typed:
highlightRange(input_box_id, charLength);
}//end type-ahead block
}//end else (num_rows >= 1)
isWorking = false;
}
}
}//end function handleHttpResponseXML
I guess I need to include the highlightRange function, too:
[-----------------------------------------------------------------------
function highlightRange(elem, start, end) {
var textbox = document.getElementById(elem);
charLength = textbox.value.length;
switch (arguments.length) {
case 1:
start = 0;
end = charLength;
break;
case 2:
end = charLength;
break;
}//end switch
if (textbox.createTextRange) {
var range = textbox.createTextRange()
range.moveStart("character", start);
range.moveEnd("character", end);
range.select();
} else if (textbox.setSelectionRange) {
textbox.setSelectionRange(start, end);
}
}//end function hightlightRange
------------------------------------------------------------------------]
Alright, so again, I know it's probably a synchronization problem.
I've tried using setTimeout, but this isn't going to solve the problem.
Also, I've found out exactly when the problem occurs. Using the same
example, let's say that "(e-mail address removed)" is the first listing that comes
up for "ja". And let's say that I'm looking for something starting
with "jas". Now, the problem occurs exactly in the following timing: I
type "ja" quickly, wait a split second and then *right before*
"(e-mail address removed)" shows up, I type in an "s" - but the result from typing
the "ja" ("(e-mail address removed)") shows up and overrides the "s" I just typed
in. Any ideas on how I can fix this problem (or synchronize the AJAX
properly)?