I am doing some work with the Rails text_field_with_auto_complete method to provide a dropdown list of completed options as a user types, like Google Suggest. However, I needed the item displayed in the dropdown to be different to the item displayed when it is selected. I couldn’t find any help online. So at first I thought I would need to override the AJAX code, but when I looked I saw text_field_with_auto_complete already had this feature built in.
To find out how to use text_field_with_auto_complete, I recommend this Railscast (I have watched about a dozen Railscasts and they have all been great). My starting setup is as described in the Railscast.
The trick to displaying something different to what was selected is to
have the field to be displayed hidden in the selection list. To do this
add a <div>
with a class into the selection item with
style='display:none'
. Thus the text in the div will not be displayed
in the dropdown, but the text is there. Put the text to show when an
item is selected into the hidden div. In the file to create the list of
selection items I had the following:
<% return unless @queues %>
<% items = @queues.map { |entry| content_tag("li","<div class='wq_display' style='display:none'>#{entry.name} </div><div class='wq_full'>#{entry.name_and_owner}</div>") } %>
<%= content_tag("ul", items) %>
Then in call to the text_field_with_auto_complete method specify
:select
in the fourth argument. The value of the :select
is the
class name of the div to use for displaying. So I used the below and
voila, the wq_full
div is displayed in the dropdown and the
wq_display
div is displayed in the text box when selected!
Queue <%= text_field_with_auto_complete :add, :queue,
{:size => 20, :maxlength => 40 },
{:url => formatted_workqueues_path(:js), :method => :get, :param_name => 'search', :select => 'wq_display'} %>
This concept can be easily extended. I also needed a third field, one containing the selection item’s id and have this passed back to the server on submit. Thus I just add a new hidden div to the selection items containing the id:
<% items = @queues.map { |entry| content_tag("li",
"<div class='wq_display' style='display:none'>#{entry.name}</div><div class='wq_full'># {entry.name_and_owner}</div><div class='wq_id' style='display:none'>#{entry.id}</div>") } %>
<%= content_tag("ul", items) %>
Then I use :after_update_element
to provide a javascript function that
runs after an item is selected. Here it sets the value of a hidden input
field to the text inside the new div.
Queue <%= text_field_with_auto_complete :add, :queue,
{:size => 20, :maxlength => 40 },
{:url => formatted_workqueues_path(:js), :method => :get, :param_name => 'search', :select => 'wq_display',
:after_update_element => "function(element,val) {
var nodes = val.select('.wq_id') || [];
if(nodes.length>0)
$('wq_id').value = Element.collectTextNodes(nodes[0], 'wq_id');
} "} %>
<input id="wq_id" name="add[wq_id]" type="hidden" value=""/>
You could also go further and update other parts of the page or have other fields, but you should get the idea for now.