Complex data in an auto-suggest

This post is more than 2 years old.

This is a question I get about once a month. Is it possible to use an autosuggest that returns complex data? What I mean is - I want to be able to start typing into a text field, see a list of matching names come up, but when I pick one, I need to know both the name value and the ID related to the name. So for example, imagine this data:

IDName
1Paris Hilton
2Darth Vader
3Victor Newman

If I type "v" and see Victor Newman pop up, when I select him I need to know that his ID was 3.

As far as I know this isn't possible with both Spry and ColdFusion 8's autosuggest. Both demand you return simple values to populate the suggestions.

You could do a lookup based on the name. So once you get the name, do another Ajax request to translate "Victor Newman" to 3. You can probably guess the problem with this. If there are two Victor Newmans, than what ID would you return? You could return names along with a middle initial, but that simply reduces the problem. It doesn't fix it. Depending on how complex you want to get though - you could do your Ajax request and when you see more than one result returned, prompt the user to pick the one they meant.

Has anyone else solved this problem? I'm thinking there has to be a better solution.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Sam Farmer posted on 5/27/2008 at 5:51 PM

I've done this by bind a cfselect to an input field. So the user types in the input field and the values appear in the select. You can set the size of the select to 5 or 10 if you want people to see it.

Comment 2 by Raymond Camden posted on 5/27/2008 at 6:07 PM

So I'm confused. Is your comment specifically talking about the issue of linking one name to N results with the same name?

Comment 3 by Trent Richardson posted on 5/27/2008 at 6:18 PM

I've never used it with ColdFusion 8 or Spry, but normally I in my json or whatever feeds the values to the type suggest I will create lists as my values of some sort, wither by number of characters or delimiters: "23|John Doe". Thats pretty easy to decode in any server side language.

Comment 4 by Doug Keen posted on 5/27/2008 at 6:41 PM

The multiple "Victor Newman" problem may be a moot point. If two "Victor Newman"s show up in your auto-suggest list, how is your user supposed to differentiate between them? Seems like there's a more critical user interface problem that underlies that hypothetical duplicate label problem... ie, you shouldn't be showing duplicates in the list in the first place (assuming the list is an identity selection and not a search term selection).

Granted, the secondary lookup of the selected label is clunky, but it does seem like a valid workaround.

Comment 5 by Boyan Kostadinov posted on 5/27/2008 at 6:42 PM

This should be pretty simple to do if you can capture or wire your own event that gets triggered after you do the select. Something like:
function afterSelect() {
// alert the value of the selected element
alert(document.getElementById(this.id).value));
}

The above has not been tested but it should give you an idea on how to implement.

Comment 6 by Sam Farmer posted on 5/27/2008 at 6:46 PM

@Ray:

This is how it would work:

<input type="text" name="lookup" id="lookup"><br />

<cfselect name="userID" id="userID"
bind="url:/index.cfm?
event=user.lookup={lookup@keyup}"
display="userName"
value="userID"
bindOnLoad="false" />

As the user types in the lookup field, it fires off a request to the server which returns a json-ed query to the select which puts the IDs and names in the right place. User then picks the correct user name and when submitting the form returns the ID.

Comment 7 by Raymond Camden posted on 5/27/2008 at 6:52 PM

Ah so technically you aren't doing a traditional autosuggest at all.

Comment 8 by Sam Farmer posted on 5/27/2008 at 7:00 PM

Yeah.

Is autosuggest old enough to have a traditional version?! Haha.

Comment 9 by Jim Priest posted on 5/27/2008 at 7:25 PM

This is easy with jQuery and Jorn's excellent Autocomplete plugin: (http://bassistance.de/jquer...

I routinely use this and then use jQuery to populate a hidden field with the user ID.

Comment 10 by Raymond Camden posted on 5/27/2008 at 7:27 PM

Thanks for sharing, Jim.

Is there anything jQuery can't do? ;)

Comment 11 by Richard Dillman posted on 5/27/2008 at 7:55 PM

It currently cant bring Coffee to my desk, but I've taken to calling my assistant Jquery to bridge that gap.

Comment 12 by Jim Ruzicka posted on 5/27/2008 at 9:11 PM

I ran into this when autosuggesting on multiple fields and displaying multiple fields...for instance: auto suggest a POC at specific location... I let the user type in the location or the first or last name of the poc and it returns the POC, Company, and City and lastly ID into the autosuggest. I append ID: at the end of it, then I parse out the ID to run another ajax query and load the complete POC data into display with other contact info and pass the ID as a hidden field.

Comment 13 by stitch posted on 5/28/2008 at 12:59 AM

This is possible with Spry. Display the autosuggest in a table:

<div id="autosuggest">
<span id="SupplierName"><input type="text" name="SupplierName" id="SupplierName" /></span>
<div id="SupplierMenu" spry:region="dsSuppliers">
<table>
<tr>
<th>Supplier ID</th>
<th>Supplier Name</th>
</tr>
<tr spry:repeat="dsSuppliers" spry:suggest="{SUPPLIERID}|{SUPPLIERNAME}">
<td>{SUPPLIERID}</td>
<td>{SUPPLIERNAME}</td>
</tr>
</table>
</div>
</div>

Tweak the Spry.Widget.AutoSuggest.prototype.setValue function in SpryAutoSuggest.js file (Spry 1.6.1 line 178)to break the string into an array of strings and populate the form:

Spry.Widget.AutoSuggest.prototype.setValue = function(str)
{
if (!this.textElement)
return;
this.textElement.value = str;
var myArray = str.split(/\|/);
document.form.SupplierID.value=myArray[0];
this.textElement.value=myArray[1];
this.showSuggestions(false);
};

Comment 14 by Raymond Camden posted on 5/28/2008 at 1:04 AM

To be fair Stich - I don't think modifying Spry to make it work is the same as 'possible' with Spry. ;)

Comment 15 by Seamus Campbell posted on 12/8/2008 at 6:42 AM

I do this by getting an array from my query,
eg <cfloop query="get_staff">
<cfset my_staff_array = ArrayAppend(staff_array, "#contact_first_name# #contact_surname# #contact_id#")>
</cfloop>
use ArrayToList to change it to a list, which cfautosuggest accepts.
<cfset staff_name_list = ArrayToList(staff_array,",")>
Then on my action page, get the id field
<cfset contact_id = ListLast(staff_name_list, " ")>

This seems to work - not sure how efficient it is

Seamus

Comment 16 by Matt Hunnell posted on 1/29/2009 at 10:18 PM

I wrestled with this issue for a while. This is what i came up with. I wanted to populate a hidden "personID" field when they selected from a "personName" cfselect. Instead, I populated a second cfselect with a bind attribute just like the clasic city/state example. If the "personID" cfselect calls a cfc that only returns one record, then it can work the same as the hidden input item that we originally wanted. finally you just have to use css to hide the second cfselect. My code is a little messy still, or else I would post it.

Comment 17 by Adam posted on 9/24/2009 at 11:59 PM

Hi Seamus -

I've added the ArrayToList function to my CFC. I am still trying to grab the ID from my list of clients.

I've used your recommendation on my action page of grabbing the ID, but I'm having no luck. Could you elaborate on how you accomplish this?

Thanks,
Adam

Comment 18 by Chad Armond posted on 2/24/2011 at 8:09 PM

I know this isn't the best approach, but it works. My return values from the CFC are in the format of:

#name# <span style='display:none'>#id#</span>

Then in my JavaScript, I strip the <span></span> from the result and put the id in a hidden field.