Using the jQuery-UI Autocomplete Widget

The latest version of jQuery-ui has an autocomplete widget. No more looking for one that will work (you get the point) with the version of jQuery that you have.

All you have to do is pull the latest one down from the jQuery-ui site and you are good to go.

First the jQuery to use the autocomplete plugin:

 
//we will be using this to cache the responses from the server
var ajaxCache = {};
 
//activate autocomplete on boxes that have the autocomplete class
$("input.auto_complete").autocomplete({
	source: function(request, response) {
		//what are we searching for
		var query_type = $(this).attr('element').attr('id');
		//the cacheterm that we use to save it in the cache
		var cachedTerm = (request.term + '' + query_type) . toLowerCase();
		//if the data is in the cache and the data is not too long, use it
		if (ajaxCache[cachedTerm] != undefined && ajaxCache[cachedTerm].length < 13) {
			//map the data into a response that will be understood by the autocomplete widget
			response($.map(ajaxCache[cachedTerm], function(item) {
				return {
					label: item.value,
					value: item.value
				}
			}));
		}
		//get the data from the server
		else {
			$.ajax({
				url: "/ajax/auto_complete.php",
				dataType: "json",
				data: {
					query_type: query_type,
					q: request.term
				},
				success: function(data) {
					//cache the data for later
					ajaxCache[cachedTerm] = data;
					//map the data into a response that will be understood by the autocomplete widget
					response($.map(data, function(item) {
						return {
							label: item.value,
							value: item.value
						}
					}));
				}
			});
		}
	},
	//start looking at 3 characters because mysql's limit is 4
	minLength: 3,
	//when you have selected something
	select: function(event, ui) {
		//close the drop down
		this.close
	},
	//show the drop down
	open: function() {
		$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
	},
	//close the drop down
	close: function() {
		$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
	}
});

The ajax/auto_complete.php would look something like this:

 
<?php
 
//make sure that we only allow valid query types
/**
 * @var array
 */
$validQueryTypes = array(
	'country',
	'city',
	'first_name',
	'last_name',
);
/**
 * @var string
 */
$column = (isset($_POST['query_type']) && in_array($_POST['query_type'], $validQueryTypes))? $_POST['query_type'] : null;
/**
 * @var string
 */
$q = isset($_POST['q'])? $_POST['q'].'%':null;
 
 
if($column && $q){
	switch($column){
		case 'country':
		case 'city':
			$q = new sQuery();
			$results = $q->from('addresses')
				//to make things simpler for the javascript, always select as value
				->column($column . ' as value')
				->where($column, $q, 'LIKE')
				->getAll();
 
			//SELECT $column as value FROM addresses WHERE $column LIKE '$q%';
			break;
		case 'first_name':
		case 'last_name':
			$q = new sQuery();
			$results = $q->from('users')
				->column($column . ' as value')
				->where($column, $q, 'LIKE')
				->getAll();
			//SELECT $column as value FROM users WHERE $column LIKE '$q%';
			break;
	}
 
	//$result is something like this:
	array(
		array('value'=>'Canada'),
		array('value'=>'America'),
		array('value'=>'Mexico'),
		array('value'=>'Netherlands'),
	);
 
	//then return it to the javascript
	echo json_encode($results);
}
exit;

Then the simplest part of the exercise:

 
City:
<input type="text" name="city" id="city" title="enter a city" class="auto_complete" />
 
Country:
<input type="text" name="country" id="country" title="enter a country" class="auto_complete" />
 
First Name:
<input type="text" name="first_name" id="first_name" title="enter a first_name" class="auto_complete" />
 
Last Name:
<input type="text" name="last_name" id="last_name" title="enter a last_name" class="auto_complete" />

And if they don’t have javascript enabled it doesn’t detract from the form (go progressive enhancement!).

Edit:

This post is pretty old, but just in-case you were wondering sQuery is this: https://github.com/SeanJA/ShoestringPHP/blob/master/library/classes/squery.class.php and there is also a better tested more standalone-y version here as a separate project: https://github.com/SeanJA/query-builder.


Related posts:

  1. JQuery and WordPress
  2. A couple useful jQuery Snippets
  3. Simple Tool Tip with jQuery
  4. A better way to use jQuery in WordPress Themes
  5. Ajaxy Pagination using jQuery

Tags: , , , , , , , , , , , , , , , ,

  • Ryan Martin

    Is querytype really necessary or can I remove that part?  I am using this with MVC3 and this is exactly the setup I want is far as caching goes but I am not sure how I can set querytype in my view since MVC doesn’t have arrays like your using in PHP.

    • http://seanja.com Sean Sandy

      Nope, it is not required. In this case I was using it to validate the query and return the correct data for that type. If you can (or have to) do it a different way in MVC3, then by all means, go ahead!

      • Ryan Martin

        Thanks!

  • Steve

    Sean, what is sQuery ? Is that a custom mysql wrapper you use. I couldn’t find it through google.

    • http://seanja.com Sean Sandy

      Any query builder really, I have one in ShoestringPHP:

      https://github.com/SeanJA/ShoestringPHP/blob/master/library/classes/squery.class.php

      I have also started building one from scratch using tdd:

      https://github.com/SeanJA/query-builder

      • Steve

        Cool, okay just wondering. I appreciate the code sample for autocomplete. This saves mucho time.
        Thanks

        • http://seanja.com Sean Sandy

          Glad it helped! I put in the generated sql as a comment below the code to help out as well, maybe it should have been on top?

          • steve

            No, where you have it is fine.. most people would see it.. i think I was in need of caffeine about that time

  • Eric

    It just doesn’t work.

    • http://blog.seanja.com/ SeanJA

      What part of it is not working for you?

  • Jay

    Was cut off
    HTML id=”ajax_container_id” style=”display:none;”

    • http://blog.seanja.com/ SeanJA

      I fixed the code up in your comment (you can use code tags here apparently), and I changed your brackets to square ones instead for the html part.

      • Jay

        Ok, thank you!

  • Jay

    Thank you for the code.
    I will appreciate your comment on this one:

    HTML

    [div id=”ajax_container_id” style=”display:none;”] [/div]

    JavaScript (source part)


    source:

    function(req, res){
    $('#ajax_container_id').html('');
    $('#ajax_container_id').load('?r=controller/action',{ request:req['term'], someotherdata:data },function(){
    if($('#ajax_container_id').html()!=''){
    res(eval('('+$('#ajax_container_id').html()+')'));
    }
    $('#ajax_container_id').html('');
    });
    },

    PHP as is or any…

    There is no caching but an idea of a shorter code.

    Thank you in advance.

    • http://blog.seanja.com/ SeanJA

      While you could possibly do it this way, I try to avoid using eval when possible. I am not really sure what you would end up with in the ajax_container_id div though…?

      • Jay

        I do agree. It’ll be better to use: JSON.parse(responseText)

        Cheers anyway.

  • Marek

    Hi

    Thanks for your tutorial. One thing you forgot is parsing json from string.

    Regards

    • Marek

      Oops sorry, everythink is ofcourse OK

  • Pingback: uberVU - social comments