Problem with Type-Ahead

Discussion in 'Javascript' started by Joel Byrd, Nov 23, 2005.

  1. Joel Byrd

    Joel Byrd Guest

    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 "". 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 "", 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 "" 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*
    "" shows up, I type in an "s" - but the result from typing
    the "ja" ("") shows up and overrides the "s" I just typed
    in. Any ideas on how I can fix this problem (or synchronize the AJAX
    properly)?
    Joel Byrd, Nov 23, 2005
    #1
    1. Advertising

  2. Joel Byrd

    Jambalaya Guest

    Joel Byrd wrote:
    > 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 "". 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 "", and consequently, narrow the search down
    > to this one listing.


    [snip]

    > function doSuggest() { getSuggest(db_table_name, db_column_name,
    > element(input_box_id).value, max_listings); }


    Here you are sending the value of the text input to the getSuggest
    function. This would include the lookahead that was placed into the
    text input by:
    [snip]

    > //Next, show the listing in the search box.
    > document.getElementById(input_box_id).value =
    > document.getElementById('listing1').innerHTML;


    So either don't put the entirety of the suggestion into the text input
    or don't send the selected portion of the text input to the getSuggest
    function.

    > Alright, so again, I know it's probably a synchronization problem.


    Nope. It's doing exactly what you're telling it to. It doesn't have
    anything to do with the AJAX. OT: You should consider using key events
    instead of a timer. There's no need to make a roundtrip to the server
    if the user hasn't typed anything.
    Jambalaya, Nov 23, 2005
    #2
    1. Advertising

  3. Joel Byrd

    Joel Byrd Guest

    But with the autocomplete, when I type a letter, any existing
    type-ahead characters automatically disappear, so that at that moment,
    what is in the input box is only what I have typed, and it is at that
    point that I call the getSuggest function, which queries the database
    with the current value of the input box, and *then* based on the
    results, creates the type-ahead characters. So, I don't see how the
    type-ahead characters could get sent to the database since the sequence
    of actions is what I just described. Even so, I know the type-ahead
    characters sometimes *are* being sent to the database. So, again, I
    think it's some sort of synchronization problem (I don't pretend to be
    any kind of javascript expert, so I certainly could be wrong about this
    - I'm just trying to understand it). In summary, the sequence of the
    code is the following (we'll assume user has already typed some letters
    so that there is already some type-ahead text highlighted):

    1) User types a letter.

    2) On keydown, the highlighted type-ahead text disappears so that now
    all that appears is what the user has typed.

    3) On keyup, the autosuggest function is called:
    getSuggest(db_table_name, db_column_name,
    document.getElementById(input_box_id).value, max_listings).

    4) The XmlHttpRequest object is used to query the database with the
    current value of the input box (which *should*, at this point, be only
    what the user has typed (see step 2).

    5) Results come back from this query, populating the drop-down suggest
    box and populating the input box with the first result, highlighting
    what the user has not typed.
    Joel Byrd, Dec 1, 2005
    #3
  4. Joel Byrd

    Joel Byrd Guest

    In fact, I just did some testing and realized that I am having the same
    problem even *without the type-ahead* functionality, so the type-ahead
    is not the problem.
    Joel Byrd, Dec 1, 2005
    #4
  5. Joel Byrd

    VK Guest

    Joel Byrd wrote:
    > In fact, I just did some testing and realized that I am having the same
    > problem even *without the type-ahead* functionality, so the type-ahead
    > is not the problem.


    I did not look your code through (it's big :)

    Just for hell of it:

    instead of:
    var randomNumber = Math.floor(Math.random() * 9999999);

    try:
    var randomNumber = (new Date()).getTime();
    VK, Dec 1, 2005
    #5
  6. Joel Byrd

    Jambalaya Guest

    Joel Byrd wrote:
    > But with the autocomplete, when I type a letter, any existing
    > type-ahead characters automatically disappear, so that at that moment,
    > what is in the input box is only what I have typed, and it is at that
    > point that I call the getSuggest function...


    It would be helpful to see all the code and the markup involved. Do you
    have it uploaded somewhere? Otherwise we are making suppositions about
    things we cannot see. I assumed you were using a timer but you are
    using key events.
    Jambalaya, Dec 2, 2005
    #6
  7. Joel Byrd

    Joel Byrd Guest

    > It would be helpful to see all the code and the markup involved. Do you
    > have it uploaded somewhere?


    Right, of course. I've copied it over to my personal school webspace.
    So here's the address: http://web.njit.edu/~jmb2/Joel/suggest.php
    Joel Byrd, Dec 6, 2005
    #7
  8. Joel Byrd

    Jambalaya Guest

    Joel Byrd wrote:
    > > It would be helpful to see all the code and the markup involved. Do you
    > > have it uploaded somewhere?

    >
    > Right, of course. I've copied it over to my personal school webspace.
    > So here's the address: http://web.njit.edu/~jmb2/Joel/suggest.php


    OK. Some testing shows that the network lag is causing the poor
    behavior. I type "ang" quickly and then it was replaced with "Aaron
    Patterson" with the "on Patterson" selected. So the result was from the
    first "a" typed. But it still respected the fact that I had typed 3
    characters when it did the selection routine.

    I think you can solve the issue if you'll cancel all previous requests
    on keydown. Then what the user types will never be replaced and only
    the last keyup will be an active request. Thoughts?
    Jambalaya, Dec 6, 2005
    #8
  9. Joel Byrd

    Joel Byrd Guest

    That thought had actually crossed my mind. Any suggestions on how to
    actually cancel a previous request?
    Joel Byrd, Dec 7, 2005
    #9
  10. Joel Byrd

    Jambalaya Guest

    Joel Byrd wrote:
    > That thought had actually crossed my mind. Any suggestions on how to
    > actually cancel a previous request?


    Most xmlhttp implementations have an "abort" method which you could
    call to cancel the processing. Just keep the previous request
    referenced by a variable and call the abort method on that variable
    when a new request is made. Should be simple...
    Jambalaya, Dec 8, 2005
    #10
  11. Joel Byrd

    Joel Byrd Guest

    Perfect! I didn't realize there was an abort method (I should have
    just googled the xmlHttpRequest object). I put an abort statement in
    the keydown handler function, and...it seems to have solved the problem
    - thanks!
    Joel Byrd, Dec 9, 2005
    #11
  12. Joel Byrd

    Joel Byrd Guest

    hehe, well it seems to have worked on my school site, but not on
    another one I tried it on. Something having to do with the network
    response, I don't know.
    Joel Byrd, Dec 9, 2005
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter

    DropDown Type ahead

    Peter, Feb 24, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    579
    Steven Cheng[MSFT]
    Feb 24, 2006
  2. Peter

    Type ahead dropdown box

    Peter, Aug 30, 2006, in forum: ASP .Net
    Replies:
    8
    Views:
    8,515
    PeterBrunone
    Sep 5, 2006
  3. Paul D. Fox

    How to do a Combo box with Type Ahead

    Paul D. Fox, Mar 23, 2005, in forum: ASP .Net Web Controls
    Replies:
    2
    Views:
    194
    Paul D. Fox
    Mar 24, 2005
  4. jpm

    dropdownlist type ahead?

    jpm, Jul 9, 2010, in forum: ASP .Net Web Controls
    Replies:
    0
    Views:
    1,087
  5. tuffs
    Replies:
    2
    Views:
    124
Loading...

Share This Page