Link to home
Start Free TrialLog in
Avatar of rodneygray
rodneygrayFlag for United States of America

asked on

Javascript autocomplete

I am working on a form that is web based and I need to include a look-up for common medications so the field auto completes.
So if someone started typing Tyl.... it would show an auto complete for Tylenol (below the field) so the user can click the word instead of typing it. Because spelling Acetaminophen  on a touch screen can take a long time and be misspelled. My target is an input id on a form and from the looks of it my only avenue is JavaScript for this. It would also be good if I could use an external file like, medicines.txt to maintain a list so I don't have them hard-coded into the form.
Avatar of Alexandre Simões
Alexandre Simões
Flag of Switzerland image

For the autocomplete, jQuery have a really nice implementation:
http://jqueryui.com/autocomplete/

Of course this might be a bit overkill if you're not using jquery ui.
Implementing it from scratch in javascrip is not that difficult either.
Also have a look at this: http://complete-ly.appspot.com/

For the data it all depends on the amount of data we're talking about.
You can either put everything in a separate js file that will be cached by most browsers but might take a while to load the first time or simply use ajax to get the data based on the user input.
Avatar of BStrignano
BStrignano

Two options, do an AJAX query back to the server with the search on the text box, personally i would recommend jQuery to facilitate this. Or you can load the list as json into a hidden text area on the form when it loads, move it into an object, and iterate over it on the onchanged event of the text box. Short circuit the javascript function not to do the lookup unless the user has typed at least three characters.
Then create (un-hide) a div beneath the box containing a list box to display the results and capture the selected value when the user clicks an item.
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@BStrignano: "Or you can load the list as json into a hidden text area on the form when it loads"
This is not a good practice.
If the data is static (like it appears here) you should put it in a separate *.js file.
This will let the browsers cache the file like any other static resource file and also, as it's already a js file the data inside should be already in the JSON form, avoiding parsing tasks.
Ex: var data = [ { }, { }, { }, ... ]

For me, if the source data doesn't really change data much, this is the best option for performance.
I would just be guessing about the list of drugs, but if the OP would show us a list of the drugs, we could suggest some ideas around the "medicines.txt" idea.  Probably suggestions would include a data base.  Some of this will depend on the other parts of the app.
Avatar of rodneygray

ASKER

I presently do not have the list of drugs that will be used I am using this as framework for other areas I will be auto completing also.
I'd like to do auto-completes on medical conditions and such as well.
Here is a strategy that you could probably extend.  See line 57 first, then look at lines 9-36

<?php // RAY_jquery_autocomplete.php
error_reporting(E_ALL);

// IF WE GOT THE SUBMITTED DATA
$q = !empty($_GET['q']) ? $_GET['q'] : NULL;
if ($q) echo "YOU CHOSE $q";

// THE OPTIONS COULD COME FROM A FILE OR DATA BASE QUERY
$options = <<<EOD
    "Apple"
  , "Banana"
  , "Carrot"
  , "Date"
  , "Eggplant"
  , "Fries"
  , "Garlic"
  , "Hummus"
  , "Ice cream"
  , "Jelly"
  , "Kumquat"
  , "Liver"
  , "Mango"
  , "Nectarine"
  , "Orange"
  , "Peach"
  , "Quiche"
  , "Rice"
  , "Salami"
  , "Tomato"
  , "Ugli fruit"
  , "Vanilla"
  , "Watercress"
  , "Xanthan gum"
  , "Yam"
  , "Zucchini"
EOD;

// CREATE THE HTML DOCUMENT USING HEREDOC NOTATION TO INJECT THE OPTIONS INTO THE JAVASCRIPT
$html = <<<ENDHTML
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />

<title>jQuery UI Autocomplete Demonstration</title>

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<link rel="stylesheet" href="http://jqueryui.com/autocomplete/resources/demos/style.css" />

<script>
$(function() {
  var availableFoods = [
  $options
  ];
  $( "#foods" ).autocomplete({
    source: availableFoods
  });
});
</script>
</head>

<body>
<form>
<div class="ui-widget">
  <label for="tags">Foods: </label>
  <input name="q" id="foods" />
</div>
<input type="submit" />
</form>
</body>
</html>
ENDHTML;

echo $html;

Open in new window

HTH, ~Ray
I have tried implementing your solution Ray but am having an issue.
Test Page

$(function() {
  var quickZip = [
    "31533"
  , "31534"
  , "31535"
  , "31510"
  , "31519"
  ];
  $( "#javatbd797485X9X110zip" ).autocomplete({
    source: quickZip
  });
});

/*
 ****** Quick City lookup ******
*/
$(function() {
  var quickCity = [
    "Alma"
  , "Broxton"
  , "Douglas"
  , "Pearson"
  , "Tifton"
  ];
  $( "#javatbd797485X9X110city" ).autocomplete({
    source: quickCity
  });
});

Open in new window

Uhh, no thanks.  Please just post the script here in the code snippet.
User generated image
Here is the source code. What should we be looking at?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
                                                                <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Autocomplete test</title>

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<link rel="stylesheet" href="http://jqueryui.com/autocomplete/resources/demos/style.css" />

<meta name="generator" content="LimeSurvey http://www.limesurvey.org" />

<!-- The following line includes jquery-ui.css or jquery-ui-custom.css from template dir, template.css and needed specific css file for survey -->
<link rel='stylesheet' type='text/css' media='all' href='/upload/templates/Original_default/jquery-ui-custom.css' />
<link rel='stylesheet' type='text/css' media='all' href='/upload/templates/Original_default/template.css' />


<!--[if lte IE 6]>
<link rel="stylesheet" type="text/css" href="/upload/templates/Original_default/ie_fix_6.css" />
<![endif]-->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="/upload/templates/Original_default/ie_fix_7.css" />
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="/upload/templates/Original_default/ie_fix_8.css" />
<![endif]-->

<!-- The following CSS hides visual elements of the progress bar from screen readers. -->
<style type="text/css" media="aural tty">
    progress-graph .zero, progress-graph .graph, progress-graph .cent { display: none; }
		</style>
	<!-- The following line includes jquery.js, jquery-ui.js, survey_runtime.js , template.js and needed specific js file for survey -->
	<script type='text/javascript' src='/scripts/jquery/jquery.js'></script>
<script type='text/javascript' src='/scripts/jquery/jquery-ui.js'></script>
<script type='text/javascript' src='/scripts/jquery/jquery.ui.touch-punch.min.js'></script>
<script type='text/javascript' src='/scripts/survey_runtime.js'></script>
<script type='text/javascript' src='/upload/templates/Original_default/template.js'></script>

<link rel="shortcut icon" href="/upload/templates/Original_default/favicon.ico" />

</head>
<body class="default lang-en groupbygroup showprogress showqnumcode-X">
    <div class="outerframe">
        <table class="innerframe">
            <tr>
                <td>
                                                <form id="limesurvey" name="limesurvey" autocomplete="off" action="/index.php/survey/index" method="post">

<!-- START THE SURVEY -->
<table class="welcome-table">
    <tr>
        <td class="survey-description">
            <noscript><span class='warningjs'>Caution: JavaScript execution is disabled in your browser. You may not be able to answer all questions in this survey. Please, verify your browser parameters.</span></noscript>
            <h1>Autocomplete test</h1><br />
            <p class='surveydescription'></p>
        </td>
    </tr>
    <tr>
        <td class="language-changer">
            
        </td>
    </tr>
    <tr>
        <td class="survey-welcome">
            <span class='surveywelcome'></span><br />
            <span class="x-questions">There is 1 question in this survey</span>
        </td>
    </tr>
</table>

<table class="navigator-table">
    <tr>
        <td class="save-all">
            			<input type='button' name='loadall' value='Load unfinished survey' class='saveall' onclick="javascript:addHiddenField(document.getElementById('limesurvey'),'loadall',this.value);document.getElementById('limesurvey').submit();" />
        </td>
        <td class="submit-buttons">
            <input type="hidden" name="move" value="movenext" id="movenext" />	<button class='submit' type='submit' accesskey='n' onclick="javascript:document.limesurvey.move.value = 'movenext';"
        value='Next' name='move2' id='movenextbtn' >Next</button>

        </td>
        <td class="clear-all">
            <input type='button' name='clearallbtn' value='Exit and clear survey' class='clearall' onclick="if (confirm('Are you sure you want to clear all your responses?')) {
window.open('/index.php/797485/move/clearall/lang/en', '_self')}" />
        </td>
    </tr>
</table>
<input type='hidden' name='sid' value='797485' id='sid' />

<input type='hidden' name='lastgroupname' value='_WELCOME_SCREEN_' id='lastgroupname' />
<input type='hidden' name='LEMpostKey' value='512271979' id='LEMpostKey' />
<input type='hidden' name='thisstep' id='thisstep' value='0' />

</form>
    		</td>
    	</tr>
    </table>
</div><script type="text/javascript" src="/scripts/expressions/em_javascript.js"></script>
<script type='text/javascript'>
<!--
var LEMmode='group';
var LEMgseq=-1;
function ExprMgr_process_relevance_and_tailoring(evt_type,sgqa,type){
if (typeof LEM_initialized == 'undefined') {
LEM_initialized=true;
LEMsetTabIndexes();
}
if (evt_type == 'onchange' && (typeof last_sgqa !== 'undefined' && sgqa==last_sgqa) && (typeof last_evt_type !== 'undefined' && last_evt_type == 'TAB' && type != 'checkbox')) {
  last_evt_type='onchange';
  last_sgqa=sgqa;
  return;
}
last_evt_type = evt_type;
last_sgqa=sgqa;

}
//-->
</script>


	</body>
</html>

Open in new window

Line 38 is where the modified code is for the words, line 7-10 are from the test example you gave me.
The next page is where the action should be happening.
For some reason it does not appear to be firing the JS and drop down.
I've tried multiple variations of it.

User generated image
template.js
                                                                                                                                /*
 * LimeSurvey
 * Copyright (C) 2007 The LimeSurvey Project Team / Carsten Schmitz
 * All rights reserved.
 * License: GNU/GPL License v2 or later, see LICENSE.php
 * LimeSurvey is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 * See COPYRIGHT.php for copyright notices and details.
 * 
 * 
 * Description: Javascript file for templates. Put JS-functions for your template here.
 * 
 * 
 * $Id:$
 *
 ****** Quick Zip lookup ******
 */
$(function() {
  var quickZip = [
    "31533"
  , "31534"
  , "31535"
  , "31510"
  , "31519"
  ];
  $( "#javatbd797485X9X110zip" ).autocomplete({
    source: quickZip
  });
});

/*
 ****** Quick City lookup ******
*/
$(function() {
  var quickCity = [
    "Alma"
  , "Broxton"
  , "Douglas"
  , "Pearson"
  , "Tifton"
  ];
  $( "#javatbd797485X9X110city" ).autocomplete({
    source: quickCity
  });
});
/*
 * The function focusFirst puts the Focus on the first non-hidden element in the Survey. 
 * 
 * Normally this is the first input field (the first answer).
 */
function focusFirst(Event)
{
	
	$('#limesurvey :input:visible:enabled:first').focus();

}
/*
 * The focusFirst function is added to the eventlistener, when the page is loaded.
 * 
 * This can be used to start other functions on pageload as well. Just put it inside the 'ready' function block
 */

/* Uncomment below if you want to use the focusFirst function */
/*
$(document).ready(function(){
	focusFirst();
});
*/



function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6.
{
   var arVersion = navigator.appVersion.split("MSIE")
   var version = parseFloat(arVersion[1])
   if ((version >= 5.5) && (version<7) && (document.body.filters)) 
   {
      for(var i=0; i<document.images.length; i++)
      {
         var img = document.images[i]
         var imgName = img.src.toUpperCase()
         if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
         {
            var imgID = (img.id) ? "id='" + img.id + "' " : "";
            var imgClass = (img.className) ? "class='" + img.className + "' " : "";
            var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' ";
            var imgStyle = "display:inline-block;" + img.style.cssText;
            if (img.align == "left") imgStyle = "float:left;" + imgStyle;
            if (img.align == "right") imgStyle = "float:right;" + imgStyle;
            if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle;
            var strNewHTML = "<span " + imgID + imgClass + imgTitle
            + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
            + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
            + "(src='" + img.src + "', sizingMethod='scale');\"></span>" 
            img.outerHTML = strNewHTML
            i = i-1
         }
      }
   }    
}

$(document).ready(function(){

});
                                                                                                

Open in new window

This seems to work OK.  Only tested on Chrome.

<?php // RAY_jquery_autocomplete.php
error_reporting(E_ALL);

// CREATE THE HTML DOCUMENT USING HEREDOC NOTATION TO INJECT THE OPTIONS INTO THE JAVASCRIPT
$html = <<<ENDHTML
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />

<title>jQuery UI Autocomplete Demonstration</title>

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<link rel="stylesheet" href="http://jqueryui.com/autocomplete/resources/demos/style.css" />

<script>
$(function() {
  var quickZip = [
    "31533"
  , "31534"
  , "31535"
  , "31510"
  , "31519"
  ];
  var quickCity = [
    "Alma"
  , "Broxton"
  , "Douglas"
  , "Pearson"
  , "Tifton"
  ];
  $( "#javatbd797485X9X110city" ).autocomplete({
    source: quickCity
  });
  $( "#javatbd797485X9X110zip" ).autocomplete({
    source: quickZip
  });
});
</script>
</head>

<body>
<form>
<div class="ui-widget">
  <label for="tags">City: </label>
  <input name="city" id="javatbd797485X9X110city" />
</div>
<div class="ui-widget">
  <label for="tags">ZIP: </label>
  <input name="zip" id="javatbd797485X9X110zip" />
</div>
<input type="submit" />
</form>
</body>
</html>
ENDHTML;

echo $html;

Open in new window

HTH, ~Ray
This was just what  I needed to get started. It sent me down the path to find the solution I needed which ended up being partially built-in to the framework I was using.
Thanks for the point and thanks for using EE, ~Ray