Saturday, 24 December 2011

Autocomplete with acts_as_taggable_on

Basic tagging sorted, I went looking for a way to add auto-complete - cos it's a nice UI improvement that's pretty common on teh intarwebs these days. I did a lot of searching, as most of the solutions seem to require switching to jquery, and for reasons of laziness (and legacy code), I don't wanna do that right now.


Luckily my searching dug up a tutorial by Michael Schuerig called: auto-completion for tag lists that works with acts_as_taggable_on and the auto_complete plugin.


It pretty much covers all the bases for tagging, so I won't repeat it all here. But I think it's awesome, because it will auto-complete on just that part of the field after the last comma - just what you need for a keyword-list.


Do read all the way to the bottom of the page, as his later updates can change the way it functions a bit.


I did make one addition myself. We have one form that lets you upload multiple items at once, with a "add a new form" link. It just repeatedly inserts a partial-template onto the end of the existing list, each time it's clicked... but because it's called *after* the "onLoad" event, the auto-complete wasn't getting added to it.


To work with that, we needed to add the installAutocompletion(); call to our addNewForm function, and also make sure that each "tags_list" field had a unique id.


I also needed to slightly update the controller code so that it could *either* take params[:my_widget][:tag_list] *or* take params[:my_widgets].first[:tag_list], because the multiple-forms-on-the-page form always sends through an array of widgets instead of just the one.


Then I realised that installAutocompletion would just keep adding autocompleters every time it was called... even to fields that already had one. So I updated the code by adding the following around everything after:


/* only add it if it doesn't already exist */
   if ($(completions.id) == null) {
       element.parentNode.insertBefore(completions, element.nextSibling);
       ... everything else after the above line too
   }

After that it was all gravy.

No comments: