Using jQuery Autocomplete to Populate Another Autocomplete – ASP.NET, ColdFusion, and PHP Examples

As requested, this post covers using one jquery autocomplete to populate another jquery autocomplete on the same page. This example will use a jquery autocomplete to choose a state then, based on the state, another jquery autocomplete will be populated with zip codes for that state. Basically, the state chosen gets used as a filter in the query for the second autocomplete.

Form

The form for the examples is the same with fields for the autocompletes (state and zip_code) plus input fields for the values returned by the autocompletes.

<form action="YOUR-FILE-HERE"  method="post">
<fieldset>
<legend>jQuery UI Multi-Autocomplete Example</legend>
<p>Start typing the name of a state or territory of the United States</p>

<p><label for="state">State (abbreviation in separate field): </label>
<input type="text" id="state"  name="state" /> <input readonly="readonly" type="text" id="abbrev" name="abbrev" maxlength="2" size="2"/></p>

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

<p><label for="zip_code">Zip (only Zips from state selected above): </label>
<input type="text" id="zip_code" name="zip_code" maxlength="5" size="15" /></p>

<p class="ui-widget"><label for="city">City:</label>
<input readonly="readonly" type="text" id="city" name="city" /></p>

<p><input type="submit" name="submit" value="Submit" /></p>
</fieldset>
</form>

jQuery

The jquery is also the same for each example. Notice that the zip_code field is initially disabled to prevent entry before the results have been filtered.

Also, note that the source and secondary URL extension will have to be modified depending on the language you are using.

$(function() {
		
			//clear values on refresh
			$('#abbrev').val("");
			$('#city').val("");
			
			$("#zip_code").attr('disabled', true);
			
			$("#state").autocomplete({
				source: "states.[cfm|aspx|php]",
				minLength: 2,
				select: function(event, ui) {
					$('#state_id').val(ui.item.id);
					$('#abbrev').val(ui.item.abbrev);
					$("#zip_code").attr('disabled', false);
				},
				change: function(event, ui){
					secondary_url = "zips.[cfm|aspx|php]?filter=" + ui.item.abbrev;
					$("#zip_code").autocomplete("option", "source", secondary_url);
				}
			});
			
			$("#zip_code").autocomplete({
				source: "",
				minLength: 2,
				select: function(event,ui){
					$('#city').val(ui.item.city);				
				}
			});
			
		});

Processing

Each programming language differs slightly in the processing. And, since there are hundreds of zip codes per state, the results are limited to 20. If the zip code desired is not returned in the top 20 after entering the minimum 2 characters, typing more characters will yield more precise results.

PHP

Refer to the example for using the jquery autocomplete with PHP. The code below only shows the zip select database processing.

PDO version

/* Connection vars here for example only. Consider a more secure method. */
$dbhost = 'YOUR_SERVER';
$dbuser = 'YOUR_USERNAME';
$dbpass = 'YOUR_PASSWORD';
$dbname = 'YOUR_DATABASE_NAME';

try {
  $conn = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
}
catch(PDOException $e) {
    echo $e->getMessage();
}

$return_arr = array();

if ($conn)
{
	$ac_filter = $_GET['filter'];
	$ac_term = $_GET['term']."%";
	$query = "SELECT zip, city FROM zips WHERE abbrev = :filter AND zip like :term  LIMIT 20";
	$result = $conn->prepare($query);
	$result->bindValue(":filter",$ac_filter);
	$result->bindValue(":term",$ac_term); 
	$result->execute(); 
	
	/* Retrieve and store in array the results of the query.*/
	while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
		$row_array['label'] = $row['zip'] . " " . $row['city'];
		$row_array['value'] = $row['zip'];
		$row_array['city'] = $row['city'];
		
        array_push($return_arr,$row_array);
    }
	
}
/* Free connection resources. */
$conn = null; 

/* Toss back results as json encoded array. */
echo json_encode($return_arr);

Non-PDO version

<?php
$dbhost = 'YOUR_SERVER';
$dbuser = 'YOUR_USERNAME';
$dbpass = 'YOUR_PASSWORD';
$dbname = 'YOUR_DATABASE_NAME';

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql');
mysql_select_db($dbname);

$return_arr = array();

if ($conn)
{
	$fetch = mysql_query("SELECT zip, city FROM zips WHERE abbrev = '" . mysql_real_escape_string($_GET['filter']) . "' AND zip like '" . mysql_real_escape_string($_GET['term']) . "%' LIMIT 20"); 
	
	/* Retrieve and store in array the results of the query.*/
	
	while ($row = mysql_fetch_array($fetch, MYSQL_ASSOC)) {
		$row_array['label'] = $row['zip'] . " " . $row['city'];
		$row_array['value'] = $row['zip'];
		$row_array['city'] = $row['city'];
		
        array_push($return_arr,$row_array);
    }

	
}
/* Free connection resources. */
mysql_close($conn);

/* Toss back results as json encoded array. */
echo json_encode($return_arr);
?>

ASP.NET

Refer to the complete example of using the jquery autocomplete with ASP.NET for more information.

<%@ Page Language="VB" Debug="false" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>


<script runat="server">
    Dim serializer As JavaScriptSerializer

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
        serializer = New JavaScriptSerializer()
        Response.Write(JSONData(Request.QueryString("Term")))
    End Sub
    
    Public Class Zip
        Public zipcode As String
		Public label As String
		Public value As String
        Public city As String
    End Class

    Private Function JSONData(ByVal term As String) As String
        
        Dim zipArray As New ArrayList
        Dim index As Integer = 0
        
        Dim objConn As New SqlConnection("Server=YOUR-SERVER;Database=YOUR-DATABASE;User ID=YOUR-USERID;Password=YOUR-PASSWORD")
        Dim myds As New DataSet("Zips")
        
        objConn.Open()

        Dim adapter As New SqlDataAdapter("SELECT TOP 20 zip, city FROM zips WHERE abbrev = @ac_filter AND zip like @ac_term + '%'", objConn)
        adapter.SelectCommand.Parameters.Add("@ac_filter", SqlDbType.VarChar)
        adapter.SelectCommand.Parameters("@ac_filter").Value = Request.QueryString("filter")
        adapter.SelectCommand.Parameters.Add("@ac_term", SqlDbType.VarChar)
        adapter.SelectCommand.Parameters("@ac_term").Value = term
        adapter.Fill(myds, "Zips")

        For Each dr As DataRow In myds.Tables(0).Rows
            Dim zp As New Zip()
            zp.label = dr("zip").ToString() & " " & dr("city").ToString()
            zp.value = dr("zip").ToString()
            zp.city = dr("city").ToString()
            zipArray.Add(zp)
        Next
        
        objConn.Close()
        
        Return serializer.Serialize(zipArray)
    End Function

</script>

ColdFusion

Refer to the complete example of using the jquery autocomplete with ColdFusion for more information.

ColdFusion’s serializeJSON function has an odd bug that will not let you send numbers as strings. This turns the zip codes into numbers which we do not want. To workaround this, I added a space in front of the zip code then removed it from the JSON output with the Replace function. Not the best idea, but it works.

<cfset returnArray = ArrayNew(1) />

<cfquery name="qryStates" dataSource="autocomplete">
	SELECT TOP 20 zip, city FROM zips WHERE abbrev = '<cfqueryparam value="#URL.filter#" cfsqltype="cf_sql_varchar">' AND zip like '<cfqueryparam value="#URL.term#" cfsqltype="cf_sql_varchar">%' 
</cfquery>

<cfloop query="qryStates">
	<cfset zipsStruct = StructNew() />
    <cfset zipsStruct["label"] = ToString(zip) & " " & city />
    <!---Had to add leading space to prevent serializeJSON from turning zip into number--->
    <cfset zipsStruct["value"] = " " & zip />
    <cfset zipsStruct["city"] = city />
    
    <cfset ArrayAppend(returnArray,zipsStruct) />
</cfloop>

<cfoutput>
<!---replaced all spaces after quotes with just quotes in JSON to remove leading space applied to zip--->
#Replace(serializeJSON(returnArray),'" ','"',"all")#
</cfoutput>

Very important information below. Please read and understand before expecting the autocomplete to work properly.

Explanation on the ‘label’ and ‘value’ fields from the jQuery UI site:

The local data can be a simple Array of Strings, or it contains Objects for each item in the array, with either a label or value property or both. The label property is displayed in the suggestion menu. The value will be inserted into the input element after the user selected something from the menu. If just one property is specified, it will be used for both, eg. if you provide only value-properties, the value will also be used as the label.”

Recommended:

Demo using PHP

Posted in .net, ColdFusion, jquery, php. Tags: , , , . Permalink. Both comments and trackbacks are closed.

41 Comments

  1. Gily
    December 23, 2011 at 12:21 pm | Permalink

    Thanks for the great tutorial.
    I am trying to adapt this script to perform a two step process:

    1. First step is the same as above, i.e. a live, auto-complete search for a term in a database.

    2. 2nd step, though, is looking into a different table in db, linked to first, and pulling out date out of there and presenting it on the front-end form as options such as radio buttons to be selected by user, rather than another auto-complete input field.

    Can you give he some idea as to how to make data coming from 2nd db query become radio buttons?

    Thanks again!

  2. Roy
    November 14, 2011 at 8:02 am | Permalink

    I decided to use a dropdown menu for the country and can’t figure out how to get the value to

    source: “cgi-bin/states.cgi?filter=” + myValue,

    It only put the first value on the dropdown no matter what I select.

  3. November 10, 2011 at 9:19 am | Permalink

    @Roy

    Is ui.item.countrycode being returned when the state is selected? If it’s not in the response with state, you need to set it as a var that the state autocomplete can put into the third_url string.

  4. Roy
    November 10, 2011 at 8:44 am | Permalink

    I have the script working ok like it is but what I need is to add one more call to another script for autocomplete.
    What I am doing is first choosing country then state then city.
    I have the country working with state but can’t get the city to work.
    I added this code but it doesn’t work.
    When I type it posts to the webpage it self.

    change: function(event, ui){
    third_url = “cgi-bin/city.cgi?filter=” + ui.item.countrycode + “&cities=” + ui.item.state;
    $(“#city”).autocomplete(“option”, “source”, third_url);
    $(“#city”).attr(‘disabled’, false);
    }

  5. March 31, 2011 at 2:54 pm | Permalink

    @tim

    I do not see the code for your other autocomplete:

    $("#workOrder").autocomplete({
    //code
    });

  6. tim
    March 31, 2011 at 12:56 pm | Permalink

    hi!
    i'm trying to do something similar to what you have here but can't seem to get the 2nd textbox to work. i'm new to this jquery stuff so please help :) I have the autopopulating working indvidually but need the 2nd one filtered. i added an alert in the change function which alerts but nothing happens, no errors in firebug. here is what i have:

    <script>
    $(document).ready(function() {
    $("input#jobCode").autocomplete({
    source: "jobCodes.cfm",
    select: function(event, ui) {
    $('input#jobCode').val(ui.item.jobCode);
    $("input#workOrder").attr('disabled', false);
    },
    change: function(event, ui){
    alert('asdf');
    secondary_url = "workOrders.cfm?filter=" + ui.item.jobCode;
    $("input#workOrder").autocomplete("option", "source", secondary_url);
    }

    });
    });
    </script>

    Thanks in advance :)

  7. lorenz
    January 14, 2011 at 10:20 pm | Permalink

    Hi Jen,
    nice work!
    maybe i need to blame this on the coffee…
    like in your tutorial i query the db for some results.
    then i put the array together and hand it over to json_encode()…

    here is some code:

    while ($row = $q->fetch_array(MYSQLI_ASSOC)) {
    $row_array['label'] = $row['VorlagenID'] . " " . $row['Subtitel'];
    $row_array['value'] = $row['VorlagenID'] . $row['Subtitel'];
    array_push($return_arr,$row_array);
    }
    echo json_encode($return_arr);

    now the json_encode() method only returns
    ["Array","Array","Array","Array","Array","Array","Array","Array","Array"]

    if i convert $return_arr into a asosiativ array the autocomplete box doesnt appear anymore…

    what am I doing wrong???

  8. December 18, 2010 at 3:59 pm | Permalink

    @Jen
    I found that if I change this line:
    <input name="hidden_industry_code" name="hidden_industry_code" type="hidden" value="industry_code">

    to:

    <input name="hidden_industry_code" name="hidden_industry_code" type="hidden" value="">

    It works perfectly as expected.

    Thanks again for such an awesome website :D

  9. December 18, 2010 at 2:56 pm | Permalink

    @Jen
    This is Terry again. I was finally able to get this script to work. It had something to do with the zip.php file (ie: I had mistyped a column name).

    I have a perplexing question…
    My code uses the following in a file I named industry.php

    while ($row = mysql_fetch_array($fetch, MYSQL_ASSOC)) {
    $row_array['industry_code'] = $row['sic_code'];
    $row_array['value'] = $row['sic_industry'];
    $row_array['industry_name'] = $row['sic_industry'];
    $row_array['label']= $row['sic_code'] . " | " . $row['sic_industry'];

    array_push($return_arr,$row_array);
    }
    When I submit my form I am able to pass the industry_name variable, however I actually need to pass the industry_code variable on to the next page.

    I have tried to create a hidden form field using:
    <input name="hidden_industry_code" name="hidden_industry_code" type="hidden" value="industry_code">

    However, nothing that I have done seems to work.
    Do you have any suggestions ?

    Thanks & Merry Christmas !

  10. December 3, 2010 at 8:11 am | Permalink

    @Marc
    Glad to hear that you got it working. Nice playlist. Lots of classic guitar rock in there.