Using jQuery UI Autocomplete with Hidden ID's
By Pete Freitag
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:
- Change the name on the existing input field to whatever it was plus
_autocomplete_label
- Create a hidden input field with a name attribute value of the original input element (this will contain my ID value).
- 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.
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:
- jQuery UI Autocomple IE 6 Select List z-Index Issues
- jQuery UI Sortable Tutorial
- Getting Started with jQuery Mobile
- JavaScript Confirm Modal using Bootstrap
The FuseGuard Web Application Firewall for ColdFusion & CFML is a high performance, customizable engine that blocks various attacks against your ColdFusion applications.
CFBreak
The weekly newsletter for the CFML Community
Comments
[{"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().
Got any suggestions on how to deal with laoding the fields with existing data, as when editing an existing entry?
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");
change: function (event, ui) {
if ( ! this.value) {
$('#'+hiddenElementID).val(');
}
},
//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.
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.
focus: function() {
$('#input_you_want_to_reset').val(');
}
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 */
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);
}
http://www.coldfusionjedi.com/index.cfm/2010/4/12/Playing-with-jQuery-UIs-Autocomplete-Control