Marko Anastasov wrote this on July 25, 2009
Hacking Rails auto_complete plugin for Prototype
The official Rails plugin for adding auto-complete functionality to your forms which works with Prototype and script.aculo.us is a fair choice which suits most cases. Plus you can always easily write your own auto_complete_for_#{object}_#{attribute}
action in the controller to replace the default query. Note that you should probably always consider doing it - by default, the generated query will do a SELECT * ALL
from the given table, while a DISTINCT
call might suffice:
def auto_complete_for_post_title input = params[post][:title].split(",").last.strip posts = Post.all( :select => "DISTINCT(title)", :conditions => ["LOWER(title) LIKE ?", "%#{input}%"], :limit => 10 ) resp = "<ul>" posts.each { |p| resp << "<li>#{p.title}</li>" } resp << "</ul>" render :text => resp end
Here we will show how to auto-complete for comma separated input. The plugin as it is will generate Javascript code which will always replace any previous value in the input field, while it is often preferred to add things up in some way (eg when entering tags).
Our fork of auto_complete adds an option to pass a custom Javascript function to be called after user selects one of the items from the suggestion list (updateElement for Ajax.Autocompleter, it might have not been available at the time the plugin was written).
<%= text_field_with_auto_complete :post, :title, {}, { :update_element => "function(el) { autoCompleteUpdate(el, 'post_title'); }" } %>
Here’s how autoCompleteUpdate can look like. We want it to keep all previous entries and replace the partial input which triggered the auto-completion with the selected item:
function autoCompleteUpdate(selectedLi, fieldId) { var values = $(fieldId).value.split(','); var oldVal = ''; for (i = 0; i < values.length - 1; ++i) { oldVal += ', ' + stripWhitespace(values[i]); } $(fieldId).value = oldVal + ', ' + $(selectedLi).innerHTML; $(fieldId).value = $(fieldId).value.substring(2); }