Autocompletion with Scriptaculous and Ajax.

Demo here | Download sample files

This tutorial supercedes my previous turtorial on autocompletion by adding further tips and tricks to make your autocompletion a much better experience for your site users The tutorial is structured in the following way:

  1. Introduction: What is autocompletion and why use it?
  2. How it works.
  3. Getting scriptaculous and building the form.
  4. Building the autocomplete server.
  5. Passing back an id to our form.

1. What is autocompletion and why use it?

I predict that most people will want to skip this section and get straight to the action, so I will keep it brief. Autocompletion is a means of helping your users when filling in forms. The most common application of autocomplete is found in your web browser’s address bar; as you type the bar makes suggestions of URLs based on previous pages visited. In our example we will query a database of musical artists and give our users suggestions as they type in an artist name field.

2. How it works.

As a user types in a specific input field on a form, on each key up event, we use JavaScript to call a script in the background using Ajax (XMLHttpRequest) features built into the Scriptaculous library. Our form will pass the currently typed text to this script and the script will return a list of suggestions which will be dynamically placed in our page. The important thing is that our user can select one of these items by mouse-click or key-stroke to populate the form field instantly.

3. Getting scriptaculous and building the form.

This implementation of autocomplete requires 3 components:

  1. The Scriptculous libraries;
  2. An HTML form with a single field;
  3. An autocomplete server script

I use PHP as my language of choice for the autocomplete server script, but I have tried to keep this tutorial abstract enough to allow you to use your language of choice. The server script is the only thing that changes for different server-side scripting languages. Download the latest version of the Scriptaculous JavaScript Libraries and include them in the head of a new HTML document as below. Don’t forget to change the paths to match your directory structure:

<script type="text/javascript" src="lib/prototype.js"></script>
<script type="text/javascript" src="src/scriptaculous.js"></script>

Now add a form to your HTML page’s body. In this form we are going to add a field that will take our search term (with both id and name attributes as “searchterm”) and an empty div with an id of “hint”. This empty div acts as a holder for our hints when they are generated. You should have some HTML looking like this:

<input type="text" name="searchterm" id="searchterm" />
<div id="hint"></div>

All we need now is to initiate a new call to Scriptaculous’ built in Ajax.Autocomplete method below our HTML code for the autocompleter – like this:

<script type="text/javascript">
new Ajax.Autocompleter(”searchterm”,”hint”,”server.php”);
</script>

The Ajax.Autocompleter takes 3 arguments: The element supplying the search string, the element to show suggestions in and the server script that will generate our suggestions. With that in place we can write the server script.

4. Building the autocomplete server.

The following server is written in PHP connecting to a MySQL database but you can your language of choice and even a flat text file or XML file for the suggestion database. My database table, “Artists”, is simple – it comprises a unique id field and an artist “name”.

As the Autocompleter sends the value of a form field as a POST variable, we can use this in our server script’s query againstthe database. All we need to do is output an unordered list for the autocompleter. Scriptaculous does the leg work of inserting the latest list into our hint box everytime the user makes a keystroke. Here is my server code in PHP

<?
// don't forget your database connection here.
echo "<ul>";
$sql = "SELECT * FROM artists WHERE name LIKE '%" . $_POST['searchterm'] . "%'";
$rs = mysql_query($sql);
while($data = mysql_fetch_assoc($rs)) {
echo "<li id=\"" . $data['id'] . "\">" . $data['name'] . "</li>";
}
echo "</ul>";
?>

Note that I have given each list item an id that is the same as that of the record. We will use this shortly for a more advanced technique. But for now we have all we need for a basic autocompleter.

5. Passing back an id to our form

Once a user has selected an item from the autocompleter, the string is entered into the textfield. Often, for the sake of efficiency and accuracy it is better to deal with the id of the item than the string name when it is passed on to the next page. To do this we can use some extra functionality of Ajax.Autocompleter along with some JavaScript that will pass the id to a hidden field in our form.

The first thing we need to add to our form is a hidden field with an id that we can reference:

<input type="hidden" id="artist_id" name="artist_id" />

Now we can use an extra piece of functionality built into Ajax.Autocompleter that allows us to pick up the id that we included in our list item from the server script. This is an extra option on our autocompleter call:

new Ajax.Autocompleter(”searchterm”,”hint”,”server.php”, {afterUpdateElement : getSelectedId});

We are telling our autocompleter to run a function called getSelectedId when an item is selected. All we need to do now is write this function to get the id and inject it into our hidden field. Insert the function below the

function getSelectedId(text, li) {
$('searchterm').value=li.id;
}

And that’s all there is to it. Of course you can be as clever as you want with your autocomplete server script. Try using the LIMIT clause in your SQL to make it run faster. Make your queries more advanced to bring back more specific results. And don’t forget the fun you can have with CSS on your hint div and the list of suggestions that it displays. If you have any implementations of autocompletion using this tutorial, please post them in the comments here.

—————————-

Single ply membrane Products

80 thoughts on “Autocompletion with Scriptaculous and Ajax.

  1. I went to download the sample files at the top of the page, but autocomplete.zip wasn’t there and there was an error message instead. Can you please put that up there?

  2. Hi,

    The demo download is not working, is there a possibility of you fixing it our emailing me a .zip of the demo directly to the above address?

    The example page looks fantastic, I would love to have the opportunity to play with this script.

  3. Thank you for having published the example. it perfectly Works.
    However it misses the part that concerns “Passing back an id to our form.”
    Can the complete example be had?
    Thanks.

  4. Hi, I liked your script a lot. How would I modify it so it searches letter by letter starting at the beginning of each word instead of searching within each word? e.g. e.g. typing M would bring up all words starting with M. Thanks!

  5. dear all
    when i am using chinese word
    it won’t worked

    $host = “localhost”;
    $database = “autocomplete”;
    $user = “root”;
    $password = “”;
    mysql_query(“SET NAMES ‘UTF8′”);
    mysql_query(“SET CHARACTER_SET_CLIENT=utf8″);
    mysql_query(“SET CHARACTER_SET_RESULTS=utf8″);

    and mysql column character is utf8 too

    how to support chinese word

  6. Working perfectly exept that its not highlighting like in the example when you press the down arrow !?! Anyone got an idea !

    But Still an awesome Script Simple Effective :oP

  7. This css overrides all other instances of ul and li… please fix

    also pressing the up arrow on the list will make the page jump when it’s scrollable

  8. I love this scripts, just one thing that can we Passing back to our form mutiple value like first_name, last_name or SSN#..etc,
    thank you very much for your scripts

  9. It is a good example for single field update. However my requirement is to update three text fields from one drop down autocomplete showing two values at a time(the third is selected from the databae but not displayed in the drop down). If possible please help.

  10. Hi,

    I seem to have a problem with passing the id of record using this. as documented in “5. Passing back an id to our form”

    I have this in my page at present.

    Select name :

    new Ajax.Autocompleter(“search”,”hint”,”server.php”, {afterUpdateElement : getSelectedId});
    function getSelectedId(text, li) {
    $(‘search’).value=li.patient_id;
    }

    Alls i get is like this :
    index.php?search=Mark jones&patient_id=&Select=Select

    I take it im doing something wrong, i havent altered any of the .js files.

    Any help appreciated.

  11. Some people have been looking to scroll their autocomplete results, but like me, are having trouble with the scrolling. Everytime I would click to scroll in Safari, the list would go away. Well I’ve played around with the javascript and discovered a fix. So far it has worked for me. In the ‘controls.js’ file I deleted this line: Event.observe(this.element, “blur”, this.onBlur.bindAsEventListener(this));
    I hope this works for the rest of you. I’ve been looking for a fix for weeks.

  12. Where do you put

    function getSelectedId(text, li) {
    $(‘searchterm’).value=li.id;
    }
    I think it should go in function.js but where

  13. Working perfectly exept that its not highlighting like in the example when you press the down arrow !?! Anyone got an idea !

    But Still an awesome Script Simple Effective :oP

  14. just add in autocomplete.php, in the style section the following lines:

    .selected{
    background-color:lightblue;}

  15. I can’t pass the id in the hidden field. I put the function
    script type=”text/javascript”
    function getSelectedId(text, li) {
    $(‘customers_fax’).value=li.id;
    }
    end script

    before my form, because if I put it after I take error because element getSelectedId is not yet set for the function Ajax.Autocompleter to call it.

    But even I tried all the ways that I can think, I did not managed to get this work, to pass the id in a hidden input field.

    My page code is :
    script type=”text/javascript”
    function getSelectedId(text, li) {
    $(‘customers_fax’).value=li.id;
    }
    end script

    form action=”" method=”post” name=”onoma” id=”onoma”
    table tr td Member Search : end td
    td
    input type=”text” id=”search” name=”search” size =”70″
    input type=”hidden” id=”customers_fax” name=”customers_fax” value=”"
    end td end tr tr td id=”hint” end td
    td      end td
    td      end td
    tr end table
    end form

    script type=”text/javascript”
    new Ajax.Autocompleter(“search”,”hint”,”server.php”,{afterUpdateElement : getSelectedId});
    end script

    And my server.php is :

    $test_echo = $_POST['search'];

    $test_echo = str_replace(“A”, “Α”, $test_echo);
    $test_echo = str_replace(“B”, “Β”, $test_echo);
    $test_echo = str_replace(“G”, “Γ”, $test_echo);
    $test_echo = str_replace(“D”, “Δ”, $test_echo);
    $test_echo = str_replace(“E”, “Ε”, $test_echo);
    $test_echo = str_replace(“Z”, “Ζ”, $test_echo);
    $test_echo = str_replace(“H”, “Η”, $test_echo);
    $test_echo = str_replace(“U”, “Θ”, $test_echo);
    $test_echo = str_replace(“I”, “Ι”, $test_echo);
    $test_echo = str_replace(“K”, “Κ”, $test_echo);
    $test_echo = str_replace(“L”, “Λ”, $test_echo);
    $test_echo = str_replace(“M”, “Μ”, $test_echo);
    $test_echo = str_replace(“N”, “Ν”, $test_echo);
    $test_echo = str_replace(“J”, “Ξ”, $test_echo);
    $test_echo = str_replace(“O”, “Ο”, $test_echo);
    $test_echo = str_replace(“P”, “Π”, $test_echo);
    $test_echo = str_replace(“R”, “Ρ”, $test_echo);
    $test_echo = str_replace(“S”, “Σ”, $test_echo);
    $test_echo = str_replace(“T”, “Τ”, $test_echo);
    $test_echo = str_replace(“Y”, “Υ”, $test_echo);
    $test_echo = str_replace(“F”, “Φ”, $test_echo);
    $test_echo = str_replace(“X”, “Χ”, $test_echo);
    $test_echo = str_replace(“C”, “Ψ” $test_echo);
    $test_echo = str_replace(“V”, “Ω”, $test_echo);

    $keywords = $test_echo;
    $search_name = ” where customers_lastname like ‘%” . $keywords . “%’ or customers_fax = ‘” . $keywords . “‘”;
    $search_name = $db->bindVars($search_name, ‘:keywords:’, $keywords, ‘regexp’);
    $sql = “SELECT customers_fax, customers_lastname, customers_firstname
    FROM customers
    ” . $search_name . ”
    “;

    $rs = mysql_query($sql);

    ul class=”lista_ul”

    php while($data = mysql_fetch_assoc($rs)) {

    li id =”php echo $data['customers_fax'];” title=”php echo $data['customers_lastname'].’ ‘.$data['customers_firstname'].’   AM : ‘.$data['customers_fax'].”;” class=”lista_li”

    php
    echo $data['customers_lastname'].’ ‘.$data['customers_firstname'].’   font color=”#0000FF”AM : end font font color=”#FF0000″‘.$data['customers_fax'].’ end font’;

    end li

    php }

    end ul

    ________________

    I had to search with LATIN characters, because there was a problem with GREEK characters. So when LATIN characters are posted, they are replaced with GREEK characters. And wehen someone wants to search records with LATIN characters in database, he can use lowercase because I replace only upercase characters.

  16. AN IMPORTANT PROBLEM SOLVED :

    Dear all, I managed to solve the problem with GREEK characters.

    Instead of using :

    $sql = “SELECT * FROM artists WHERE name LIKE ‘%” . $_POST['searchterm'] . “%’”;

    BEFORE THIS ADD THIS LINE :

    $my_search = mb_convert_encoding($_POST['search'], “ISO-8859-7″, “auto”);

    IN THE LINE ABOVE, CHANGE ISO-8859-7 TO FIR YOUR LANGUAGE ISO OR WHATEVER ENCODING YOUR LANGUAGE IS USING.

    THEN CHANGE A LITTLE BIT YOUR $sql VARIABLE LIKE THIS:

    $sql = “SELECT * FROM artists WHERE name LIKE ‘%” . $my_search . “%’”;

    I was trying over 20 hours to find out how to do this, but I managed to find out after a good sleep and a good google search. And YES , I found it here :

    http://gr.php.net/manual/en/function.mb-convert-encoding.php

    Where else ?

    I hope this can help many of you. I am also preparing some code to automatically find what type of charset the user is typing, and change the encoding automatically, or java alert the user if a charset is restricted.

    Another big problem is that I still can’t pass the id to the hidden input field, so I decided to extract it from a string after my form is posted. I will post the code when it’s ready.

    Thanks to all of you.

  17. If you want to implement step 5, just put the function immediately below Ajax.autocompleter. So it looks like this:

    new Ajax.Autocompleter(“name”,”hint”,”search.php”,{afterUpdateElement : getSelectedId});
    function getSelectedId(text, li) {
    $(‘hidden’).value=li.id;
    }

    Note that you set the value of the hidden field to li.id, not the value of searchterm.

    Also, if you want the text to highlight when you press the down arrow, add this to your css:

    li.selected { background: #ffc; }

    I noticed this was in the example code but in the downloadable code.

  18. @Richard The setting of id is purposely done. The id in the list item reflects the primary key of the item selected. Once it is passed on it is much more efficient and accurate to select the item from the database by it’s primary key.

    I never placed this in the downloadable code as it was an update to the additional article. Moreover I like my students to fill some of the blanks in themselves so I know they are learning ;)

  19. @Richard & Tim
    I would like to go a little bit further for the step 5 :
    it could be great to know if the value of the search field is due to the selection of an autocomplete result (an existing item), or a totally new item typed in the form with no selection.
    So, for instance, if the returned list is empty, a script could set the hidden field to ‘new’…
    But the afterUpdateElement only works after an item selection. My script would require to get the full ajax response, to know if the list is empty or not.
    Would you have an idea of how to do that ?
    Thanks :)

  20. @Yako This should be really simple. If your hidden id field is populated with a real id from the database you can use the record on the script that collects the data. If it is empty or non-existent then you have to create a new record.

    Tim

  21. @Tim,
    Thank you for your answer
    Well, I would like it to be simple ; consider this sequence of the user action :
    1. at first hidden field is empty
    2. I select a record from the autocompleter -> the hidden field is populated
    3. I modify the text field, for any reason… Such as a mistake, or changing my mind… And i type in a new item.
    Then there is a problem, as the hidden value id does not match the field value.
    That’s the reason why I would like to update the hidden field value to nothing when no selection is made…

  22. I finally foud a solution (withe the help of Gwyohm) :

    The idea is to build an extra function which listens to the keys pressed. A key pressed means that the user is typing something new, unless he uses the enter key for selection. That’s the reason why the enter key is removed form the listener…

    $(id-of-text-field).observe(“keyup”, function(e) {

    if (window.event) keycode = window.event.keyCode;
    else if (e) keycode = e.which;
    if (keycode!=13) {

    $(id-of-hidden-field).value=”FALSE”;

    }

    }.bindAsEventListener($(id-of-text-field)));

  23. Yako, any chance you could post a download link to a complete demo that -
    a) passes the id of the selected id
    b) fixes the issue that i can use the down arrow to select a field like in the demo
    c) leaves placeholder for code, if what is entered is not in the list

    alternatively, please email me the zip ( if you can to rahul@totalcarenetwork.com)

    This is most appreciated.

  24. Tim you are obviously a great teacher. But looks like i am not so good newbie. For the life of me cannot figure out, why in your demo, you can use the down arrow but i cannot use the down arrow to scroll down the results?

  25. I am trying to get this to work, and the server.php file works flawlessly, and displays everything i am searching for. And has the id set to the id of the record.

    But!!! When I am on my search form, the div hint, does nothing, and it seems that there is nothing going on. i search and search for known values, and nothing is displayed.

    Thanks for the tutorial. I know it works., just not for me yet.

  26. I think that the down arrow problem people are experiencing is because the scriptaculous library fires on the keypress event, the behavior of this event is tricky particularly when using the prototype event observers. Attaching to key up should fix the issue.

  27. For the life of me I can not get this script to pass the hidden ID. Can anyone help me with this?
    server.php list building: <li id=”">
    autocomplete.php form:

    Type here

    new Ajax.Autocompleter(“search”,”hint”,”server.php”);
    new Ajax.Autocompleter(“C_ID”,”hint”,”search.php”,{afterUpdateElement : getSelectedId});
    function getSelectedId(text, li) {
    $(‘C_ID’).value=li.id;
    }

    What am I doing wrong?

  28. I really like the script that you have built and would like to use it in an project I am working on. However, I can’t figure out for the life of me how I can make it return the results when I search for items in a (MySQL DB) column other than ‘title’.
    I had the script working with ‘title’ and to test it with a different column name I changed the column name to ‘title1′ in the DB and then modified the $sql string in server.php to this:
    $sql = “SELECT title1 FROM autocomplete_demo WHERE title1 LIKE ‘%” . $_POST['search'] . “%’”;
    I seem to get results back because the suggest window is there and resizes (in IE) but only blank values are displayed.

    What else do I have to change in the code to work with a different column name?

    Sorry I am such a newb.

    Thx,
    TekMason

  29. This autocompleter works perfectly. I’ve been able to manipulate it quite a bit to get incredible results using it for my site. See it in action at http://www.searchforitlocal.com . I’d like to be able to use the arrow keys to scroll through the hints but I can’t seem to figure out how to make it work. Has anyone experimented with this?

  30. I can’t pass back to hidden element. Please help! :((

    The codes;

    Type here

    new Ajax.Autocompleter(“search”,”hint”,”server.php”, {afterUpdateElement : getSelectedId});
    function getSelectedId(text, li) {
    $(‘artist_id’).value=li.id;
    }

  31. This may be the problem if you cannot scroll the results with navigation arrows or the mouse: check your function that returns the results. The default autocomplete expects an unordered list. If accidentally your unordered list is *within* your loop, then depending on your CSS styles, you may see the results as a list, but in fact it is many lists containing only one item. The arrow keys and mouse completion work perfectly in this case, except that since the top list contains only one item, there is no scrolling or selecting to do.

    Hope this helps.

  32. I can’t even get the demo to work…it just doesn’t bring up any results. It shows a little empty box underneath the input box when I type, but no names show up. Does anybody have any advice?

  33. @Tim,
    I actually got it to work, it involved changing the echo statements in server.php. Thanks for this great code. Do you know how to implement arrow key functionality for the results list?

  34. Mark, even I am facing the same problem. There are no js errors etc. I type the letters th in the text field and an empty box appears beneath the input box. So, what was the change you did exactly? Could you send me the modified source code if you can? Thanks in advance

  35. Hello Tim, Thanks for such excellent tutorial. After reading article and comments, I have autocompletion working on my page. I sincerely appreciate your effort in writing this article.

    I noticed that after a list item is selected through enter/tab/mouse click, user has to press enter for submitting the form. Is there any way to submit the form immediately after selecting the list item (through the enter key)? That is, hit enter key just once for 2 actions, to select a list item and submit the form.

    I understand that you are a professional web developer so sorry for the request for help.

    Thanks,
    Yogesh

  36. Nice work Tim! I have a challenge. I want to create a web form with multiple text fields, each representing a different field from the database table and I want to implement the Autocompletion on each of them individually. So, text box one draws values from the Name field in the table, text box two draws values from the City field in the table, text box three draws from the Country field and so on. Any idea how to implement multiple autocompletes on the same form with each text box talking to different fields in the same table? Any insight would be greatly appreciated.

  37. Hi!!, I manage to get the script working and the autocompletion works excelent with my website, but I desperately need to get it work with the ID pass (step 5) I can’t get it to work, there are some things that i don’t understand like the li variable or how exactly does it get the id of the selection, do I have to modify the server.php?? please help!! if someone has solved it please help us!!!
    Thank you in advance

  38. It works!!! I just had a problem with the il tag I wasn’t writing correctly the id between the thanks to CHARIS comment I realize that. Thanks!!
    I would like to know if it is possible to delay a little bit the script, my db is huge and if I tape only an a or I take too long to write on the field, it starts looking for all the occurrences of a so it takes like a million minutes, or perhaps to start looking when the input field has at least three letter??
    Anyway the script is brilliant!!! Thank you very much!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>