Pete Freitag Pete Freitag

Using jQuery UI Autocomplete with Hidden ID's

coldfusion

The new autocomplete widget in jQuery UI 1.8 is a nice addition. While it works great for basic purposes working with ID / value pairs is not so nice out of the box.

I wanted to use the autocomplete widget to allow someone to select an employee by typing in an employee name into the text box, but I want the form to post the ID of the employee, not the employee name.

First you need to setup your server side search script, I'm using ColdFusion here:

<cfparam name="url.term" default="">
<cfset emp = empDAO.searchByName(url.term)>
<cfset result = ArrayNew(1)>
<cfoutput query="emp">
	<cfset s = StructNew()>
	<cfset s["label"] = emp.FullName>
	<cfset s["value"] = emp.EE_ID>
	<cfset ArrayAppend(result, s)>
</cfoutput>
<cfset json = SerializeJSON(result)>
<cfcontent reset="true" type="application/json"><cfoutput>#json#</cfoutput><cfabort>

The jQuery UI autocomplete widget sends a variable in the query string called term which contains the text the user has typed in. You need to return an array of objects in JSON. For example, your output might look like this:

[{label:"Pete Freitag", value:1}, {label:"Pete Doe", value:2}]

Now the HTML code I am using in the form simply looks like this:

<input type="text" name="EmployeeID" value="" class="employeeAutocomplete" />

Next I need to write some jQuery JavaScript that applies the autocomplete widget to any input tag with the employeeAutocomplete, this code would go in your $(document).ready() event handler:

$('input.employeeAutocompete').autocomplete({source:'employee-search-json.cfm'});

Now this works well up to this point, but when I select an item it put's the employee ID in the text box. From the user perspective this doesn't make any sense. What I want is for the employee's name to be put in the text box, and have a hidden field containing the employee ID passed in the form.

So to accomplish that I need to do a bit more JavaScript, I'm going to do the following:

  1. Change the name on the existing input field to whatever it was plus _autocomplete_label
  2. Create a hidden input field with a name attribute value of the original input element (this will contain my ID value).
  3. Create a custom select event handler for the given jQuery UI autocomplete instance.

So here's my new code:

$('input.employeeAutocomplete').each(function() {
	var autoCompelteElement = this;
	var formElementName = $(this).attr('name');
	var hiddenElementID  = formElementName + '_autocomplete_hidden';
	/* change name of orig input */
	$(this).attr('name', formElementName + '_autocomplete_label');
	/* create new hidden input with name of orig input */
	$(this).after("<input type=\"hidden\" name=\"" + formElementName + "\" id=\"" + hiddenElementID + "\" />");
	$(this).autocomplete({source:'employee-search-json.cfm', 
		select: function(event, ui) {
			var selectedObj = ui.item;
			$(autoCompelteElement).val(selectedObj.label);
			$('#'+hiddenElementID).val(selectedObj.value);
			return false;
		}
	});
});

Now when I submit the form the value of the EmployeeID field will be an employee ID, and the text box will simply show the employee name.

Would be cool if this widget supported an option to do what I just did, but it only takes a few additional lines of code to accomplish.


Like this? Follow me ↯

Using jQuery UI Autocomplete with Hidden ID's was first published on July 14, 2010.

If you like reading about jquery, jqueryui, autocomplete, javascript, js, or coldfusion then you might also like:

FuseGuard Web App Firewall for ColdFusion

The FuseGuard Web Application Firewall for ColdFusion & CFML is a high performance, customizable engine that blocks various attacks against your ColdFusion applications.

Comments

Unless I am not understanding what you are after, the AutoSuggest widget already provides this functionality. Check out

http://www.coldfusionjedi.com/index.cfm/2010/4/12/Playing-with-jQuery-UIs-Autocomplete-Control
by Mike on 07/14/2010 at 2:13:31 PM UTC
@Mike Ray's code example there still has javascript to set the hidden ID, he's not using anything builtin to do that. We are both using the select event to do that, the main difference is that my code creates the hidden form field dynamically, Ray's code has it in the HTML to start with.
by Pete Freitag on 07/19/2010 at 10:41:39 AM UTC
Pete - be aware that using jQuery 1.4 you need to return valid JSON which means keys are quoted too:

[{"label":"Pete Freitag", "value":1}, {"label":"Pete Doe", "value":2}]

It's possible UI is using getAJAX and then eval'ing it but jQuery 1.4 core has already switched to requiring strict JSON for requests like getJSON().
by Brian on 07/19/2010 at 8:27:06 PM UTC
This Was Awesome! Thank you for solving this puzzle. I spent a morning trying to grasp why the jQuery UI autocomplete was not doing what seemed obvious (to me at least), then found your excellent post. You've saved me a handful of hair.
by Alan McCollough on 08/26/2010 at 8:30:30 PM UTC
Got a question. I've used your autocompleter workaround, and it's fantastic for filling out a new form.

Got any suggestions on how to deal with laoding the fields with existing data, as when editing an existing entry?
by Alan McCollough on 08/27/2010 at 8:21:28 PM UTC
fwiw, I betcha you meant the spelling of "autoCompelteElement" to be "autoCompleteElement". Still works though, and again let me thank you for a very useful component!


Okay, I'll answer my own question. It was pretty obvious, really.
if field name is "foo" and it should preload with a value of "fflintstone" and label of "Flintstone, Fred", this would work for pre-populating those values.

$("input[name=foo_autocomplete_label]").val("Flintstone, Fred");
$("input[name=foo]").val("fflintstone");
by Alan McCollough on 09/03/2010 at 3:34:45 PM UTC
I'm having an issue using this method for some strange reason. When I have more than one item in the list and I hit my down arrow key on the keyboard to sift through the options, the value (ID) is displayed in the textbox as I scroll through the items. What method is doing this?
by Keith on 09/09/2010 at 4:05:58 AM UTC
I found a glitch when you focus on the input and delete the value with backspace, the select event won't fire obviously, but the change event will. So you should add this event:

change: function (event, ui) {
if ( ! this.value) {
$('#'+hiddenElementID).val(');
}
},
by Rafi B. on 11/16/2010 at 5:43:41 PM UTC
I'm also having the same issue as Keith in comment #8 above. Can't figure out why using arrow keys displays the ID numbers and not the correct letters.
by Travis on 12/10/2010 at 11:39:47 PM UTC
Do you prefer jquery or prototype for js and ajax functionality? If so, why? Ruby on Rails crowd favor Prototype, I don't have enough experience in either.
by Pardeep on 02/21/2011 at 12:23:22 PM UTC
Just to let you know, i found an easyest workaround, but haven't tested it's side effects, but simply, after the success: function(event,ui) {

//do this:
event.preventDefault();
}

it worked for me and it doesn't change the value of the text field. I've to save id somwhere to further submit, but that's ok right now.
by Kaspar Kappstein on 05/14/2011 at 7:33:48 PM UTC
Great tips, both in the tutorial and the comments. jQueryUI Autocompleter working much much better after implementing some of these.
by Andrew on 06/30/2011 at 12:41:38 PM UTC
Kaspar and Premik - thanks for the preventDefault tip, that solves my problem.

I'm using autocomplete to display "CITY, STATE, ZIP", in my city field (to disambiguate city names), and auto-populating all three fields with their appropriate elements. Works a treat.
by RET on 07/11/2011 at 8:13:02 PM UTC
I am using a hidden field to accomplish the same task but have noticed that if you press the back button after submitting the form the hidden value is still set but the autocomplete input is not not. How can you reset the hidden field or set the autocomplete to the current value?
by Craig on 08/05/2011 at 3:32:27 PM UTC
Craig, I had the same question, after studying the jquery ui doc I found that you can set the focus event like this:

focus: function() {
$('#input_you_want_to_reset').val(');
}
by Jon on 09/25/2011 at 2:56:40 PM UTC
When using this jQuery snippet in PHP, valid PHP form element names which use square brackets will fail. For example, foo[bar] is an invalid id in HTML and for jQuery. Such an id either must be escaped or the code altered as below. Otherwise, the cloned form element's value is not set since jQuery can't find the element by id anymore.

I simply changed the snippet as such so the new element's id is not the same as the old element's name:

var formElementName = $(this).attr('name');
++var formElementId = $(this).attr('id');
--var hiddenElementID = formElementName + '_autocomplete_hidden';
++var hiddenElementID = formElementId + '_autocomplete_hidden';
/* change name of orig input */
by MichaelG on 01/06/2012 at 5:51:59 PM UTC
this ok, but missing something. when the autocomplete come out, press arrow down /up using your keyboard. then, it will pass the id on the textbox (before i press enter). i try make the textbox color to white when autocomplete open.. but i still can see it when i highlight the txtbox. any good suggestion?
by hamzah on 01/25/2012 at 4:18:37 PM UTC
What if I have multiple selection enabled using autocomplete the trouble is if user deletes the selection I need to be able to delete the id associated too
by John on 02/09/2012 at 7:18:51 AM UTC
To fix the problem with the id numbers showing in the list...

There's nothing to prevent you from adding additional properties to the "item" at the time you retrieve the data, and then using those properties in the "select: function()". I.e. you aren't limited to simply the "label" and "value" being used by the standard autocomplete. I suggest the following:

In the "source" we use ajax to get the data, note that Value and Label are BOTH mapped to the "text" field in the result, and a new property, called "id" is mapped to the id value!

source: function (request, response) {
$.ajax({
url: "/Customer/Lookup",
type: "POST",
dataType: "json",
data: { searchText: request.term, maxResults: 25 },
success: function (data) {
response($.map(data, function (item) {
return { label: item.text, value: item.text, id: item.id }
}))
}
})
},

...Now in select: we use the "id" property to set the value of the hidden field, and we never have to worry about the vanilla auto-complete functionality...

select: function (event, ui) {
var selectedObj = ui.item;
$(autoCompelteElement).val(selectedObj.label);
$('#'+hiddenElementID).val(selectedObj.id);
}
by CList on 05/03/2012 at 7:26:07 AM UTC