A while back a reader (Bobby Tuck) asked me about how to do autocomplete in a jQuery Mobile application. He tried using jQuery UI's autocomplete control but found it didn't integrate well on a mobile device with the keyboard popped up. I suggested an alternative and (finally!) got around to building a mockup. Here's my take on it - feel free to rip it apart and suggest alternatives and improvements.

Let's begin with a simple jQuery Mobile template.


<!DOCTYPE html>
<html>
<head>
<title>Autocomplete Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
</head>

<body>

<div data-role="page" id="mainPage">

	<div data-role="header">
		<h1>Autocomplete Example</h1>
	</div>

	<div data-role="content">

		<p>
		<input type="text" id="searchField" placeholder="Search">
		</p>

	</div>

	<div data-role="footer">
		<h4></h4>
	</div>

</div>

<script>
$("#mainPage").on("pageshow", function(e) {
	console.log("Ready to bring the awesome.");

});
</script>

</body>
</html>

I've got a few things going on here to prepare for the autocomplete control. I've got a text field that will accept the user input. I've got a page event handler (this is jQuery Mobile specific) that will fire when the page loads. Now let's talk about my proposed solution.

I thought it might be handy to use a jQuery Mobile listview to render the suggestions. So I began by adding an empty list view beneath my form field:


<p>
<input type="text" id="searchField" placeholder="Search">
<ul id="suggestions" data-role="listview" data-inset="true"></ul>
</p>

I then wrote some simple code to handle changes to the input field.


$("#mainPage").on("pageshow", function(e) {
	console.log("Ready to bring the awesome.");
	var sugList = $("#suggestions");

	$("#searchField").on("input", function(e) {
		var text = $(this).val();
		if(text.length < 1) {
			sugList.html("");
			sugList.listview("refresh");
		} else {
			$.get("service.cfc?method=getSuggestions", {search:text}, function(res,code) {
				var str = "";
				for(var i=0, len=res.length; i<len; i++) {
					str += "<li>"+res[i]+"</li>";
				}
				sugList.html(str);
				sugList.listview("refresh");
				console.dir(res);
			},"json");
		}
	});

});

The code is rather simple I think. We bind to the "input" event for the text field and check the value. Now - most autosuggest controls make a determination on whether or not it makes sense to fire off a request. You may - for example - decide you only want to ask for autocomplete results when the user has entered 3 or 4 characters. Mine will always fire as long as you have at least one character. I did that because my data (a list of names) was a bit short and I wanted to ensure that the demo was easy to use. Obviously you can alter that to your liking.

If the user entered something, we fire off a request to the server. (In this case to a ColdFusion script that performs a search against a list of names. It's trivial enough that I won't include it in this blog entry, but if anyone wants it, you can view it here: http://pastebin.com/pFGggRc3) The server responds with an array of names. We can then take that array and create a simple HTML string out of it. This string is inserted into our empty list and then we simply call the jQuery Mobile refresh method to ensure it is marked up correctly.

And that's it. I tested it on my mobile device and while the keyboard will cover some of the results, it seems to work well:

Obviously this demo needs a bit more work to be complete. Your list options would probably link to the detail for your search results. You can find the demo below as well as the complete code.

Demo is removed as I no longer run ColdFusion on my server. Here is a link to a zip: https://static.raymondcamden.com/enclosures/27.zip


<!DOCTYPE html>
<html>
<head>
<title>Autocomplete Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
</head>

<body>

<div data-role="page" id="mainPage">

	<div data-role="header">
		<h1>Autocomplete Example</h1>
	</div>

	<div data-role="content">

		<p>
		<input type="text" id="searchField" placeholder="Search">
		<ul id="suggestions" data-role="listview" data-inset="true"></ul>
		</p>

	</div>

	<div data-role="footer">
		<h4></h4>
	</div>

</div>

<script>
$("#mainPage").on("pageshow", function(e) {
	console.log("Ready to bring the awesome.");
	var sugList = $("#suggestions");

	$("#searchField").on("input", function(e) {
		var text = $(this).val();
		if(text.length < 1) {
			sugList.html("");
			sugList.listview("refresh");
		} else {
			$.get("service.cfc?method=getSuggestions", {search:text}, function(res,code) {
				var str = "";
				for(var i=0, len=res.length; i<len; i++) {
					str += "<li>"+res[i]+"</li>";
				}
				sugList.html(str);
				sugList.listview("refresh");
				console.dir(res);
			},"json");
		}
	});

});
</script>

</body>
</html>

P.S. So hey - what about the HTML5 Datalist option? Unfortunately on mobile it is only supported in Opera. You can find details on support here: http://caniuse.com/#feat=datalist