Back to Blog

Get in Touch

Tag Type-Ahead with Multiple Items

By Dave Naffis August 6, 2007 in

Missing

If you've ever implemented type-ahead functionality and wondered how to get it to work when users are entering multiple items, like a list of comma delimited tags, here it is.

You can, of course, roll your own Javascript and Ajax calls but why bother when Rails gives us a nice Javascript helper to handle this. The helper is text_field_with_auto_complete but this defaults to the current controller. For my purposes tags can be entered on different areas of the site for different models so I used text_field_with_auto_complete with one modification:

def text_field_with_auto_complete_with_custom_url(object, method, url_options = {}, tag_options = {}, completion_options = {})
  (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
  text_field(object, method, tag_options) +
  content_tag("div", "", :id => "#{object}_#{method}_auto_complete", :class => "auto_complete") +
  auto_complete_field("#{object}_#{method}", { :url => { :action => "auto_complete_for_#{object}_#{method}" }.update(url_options) }.update(completion_options))
end 

Note: text_field_with_auto_complete is deprecated and will be moved to a plugin in Rails 2.0.

The third parameter is now a hash of optional url arguments (action, controller, etc). You can also monkey patch the original method or better use some alias/alias_method_chain trickery in your own app. In your view call the newly created helper with your arguments.


<%= text_field_with_auto_complete_with_custom_url :tag, :names, 
    {:controller => "tagging_demo"}, {}, { :tokens => ','} %>      

Include the necessary javascript libraries (prototype and scriptaculous):

<%= javascript_include_tag 'prototype' %>
<%= javascript_include_tag 'scriptaculous' %>

You can set the controller and action to whatever you like but it defaults to a method in the form of auto_complete_for_object_method. Going with that your action could look something like this:

def auto_complete_for_tag_names
  @tags = Tag.find(:all, 
    :conditions => ["name like ?", "%#{params[:tag][:names]}%"], 
    :order => 'name DESC', :limit => 20)
  render :layout => false
end

And your view (auto_complete_for_tag_names.html.erb):

    <% for tag in @tags do -%>
  • <%= tag.name -%>
  • <% end -%>

That's all there is to it. The magic comes from providing a token to Ajax.Autocompleter which we provided in the argument hash to text_field_with_auto_complete_with_custom_url ( { :tokens => ','} ). You can use any delimiter you like. You can also customize the UI in your view and CSS.

Here's a demo http://www.naffis.com/demos/tagging_demo

Medium

Dave Naffis

David is an entrepreneur and software developer with demonstrated experience in software services, product development, strategy, and operations. He is a co-founder of Intridea, an Inc 500 winning software development firm where he oversaw several successful product spinouts. Before starting Intridea, Dave ran his own Ruby on Rails consultancy and worked as a software engineer and architect at companies including AOL, Cisco, and McKinsey. He holds a masters in Systems Engineering from The University of Virginia, has contributed to a number of open-source projects, and has spoken at numerous regional and national conferences.

More posts by Dave Naffis

Dave Naffis

Four years ago, what started as a team of three people with a conviction t...

Dave Naffis

In this new blog series, Why Your Company Needs a Rails Development S...

Dave Naffis