4

I'm trying to install the twitter-typeahead-rails gem into my app. I've followed several different tutorials but all of them result in errors.

Does anyone have a working example of this gem?

Joe Morano
  • 1,715
  • 10
  • 50
  • 114

2 Answers2

9

Specify gem as dependency in your Gemfile:

# Gemfile

gem 'bootstrap-multiselect-rails'

Require typeahead files in your manifest:

// app/assets/javascripts/application.js

//= require twitter/typeahead
//= require twitter/typeahead/bloodhound

Javascript:

// app/assets/javascripts/models_controller.js

// initialize bloodhound engine
var bloodhound = new Bloodhound({
  datumTokenizer: function (d) {
    return Bloodhound.tokenizers.whitespace(d.value);
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace,

  // sends ajax request to /typeahead/%QUERY
  // where %QUERY is user input
  remote: '/typeahead/%QUERY', 
  limit: 50
});
bloodhound.initialize();

// initialize typeahead widget and hook it up to bloodhound engine
// #typeahead is just a text input
$('#typeahead').typeahead(null, {
  displayKey: 'name',
  source: bloodhound.ttAdapter()
});

// this is the event that is fired when a user clicks on a suggestion
$('#typeahead').bind('typeahead:selected', function(event, datum, name) {
  doSomething(datum.id);
});

View:

<-- app/views/models/whatever.html.erb -->

<input type="text" id="typeahead">

Routes:

# config/routes.rb

get 'typeahead/:query' => 'models#typeahead'

Controller:

# app/controllers/models_controller.rb

def typeahead
  render json: Model.where(name: params[:query])
end

## note:  the above will only return exact matches.
## depending on the database being used,
## something else may be more appropriate.
## here is an example for postgres
## for case-insensitive partial matches:

def typeahead
  render json: Model.where('name ilike ?', "%#{params[:query]}%")
end

GET request to /typeahead/%QUERY returns json in the form of:

[
  {
    "name": "foo",
    "id": "1"
  },
  {
     "name": "bar",
     "id": "2"
  }
]
ihaztehcodez
  • 2,123
  • 15
  • 29
  • It's javascript, so drop it in the javascript file that corresponds to your controller or whatever is appropriate for your app. Make sure it runs _after_ the DOM is ready. If you're using turbolinks (rails 4+): `$(document).on('page:change', function() { // DOM is ready in here });`. – ihaztehcodez Jan 23 '15 at 03:08
  • What do you have in your view? – Joe Morano Jan 23 '15 at 03:35
  • All you need in the view is a text input. I updated my answer for completeness. – ihaztehcodez Jan 23 '15 at 03:49
  • Wait, so how do I link that to actual data to search through? – Joe Morano Jan 23 '15 at 13:18
  • I updated the answer to include example route and controller code. The line `remote: '/typeahead/%QUERY', ` tells typeahead to make an ajax request to `/typeahead/%QUERY` to fetch data based on user input. – ihaztehcodez Jan 24 '15 at 02:13
  • Does that work for you? I mean with just that code, does the text input bring up suggestions as you type? – Joe Morano Jan 24 '15 at 15:32
  • Yes, this code is taken form an app that I maintain (with some variable and field names that are specific to the app changed to be more generic). – ihaztehcodez Jan 25 '15 at 08:39
  • I updated my answer to include that typeahead/bloodhound files need to be required in `application.js` manifest. I can't think of any other relevant code that I haven't provided an example of. – ihaztehcodez Jan 25 '15 at 08:47
  • @ihaztehcodez i have followed your directions and am trying to implement typeahead for multiple attributes.However i am not getting any json response when putting in my url.Here is the link: http://stackoverflow.com/a/28658253/815929 – rnjai Feb 23 '15 at 04:54
  • 1
    This is a great answer. One thing that may not be obvious: the `typeahead` method in the controller needs to handle some kind of wildcard/substring search. As is, you're probably going to get an empty result. I suspect this is the problem that @rnjai is encountering. – klenwell May 02 '15 at 18:26
  • Thanks for the feedback, @klenwell, that's a good point. I guess when I was creating a generic example that got lost in translation. I updated my answer to point that out and give a better example that is specific to postgres. – ihaztehcodez May 04 '15 at 04:01
5

The accepted answer is not completely correct.

There seem to be 2 different gems doing roughly the same thing:

bootstrap-multiselect-rails is currently on version 0.9.9 in the gem repository and has a different asset require structure as mentioned in the post. This gem's assets need to be included as:

In application.js:
//= require bootstrap-multiselect

In application.css:
*= require bootstrap-multiselect

More on Git: https://github.com/benjamincanac/bootstrap-multiselect-rails

Alternatively, there is the twitter-typeahead-rails gem, currently on version 0.11.1 which seem to need to be used and included as described in the rest of the accepted answer.

More on Git: https://github.com/yourabi/twitter-typeahead-rails

Both gems seem to be last updated about 5-6 months ago at the moment of writing this.

Finally, the remote URL specified in the Bloodhound JS is incorrect:

remote: '/typeahead/%QUERY'

Needs to be

remote: {url: '/typeahead/%QUERY', wildcard: '%QUERY'}

Hopefully this helps someone

ChrisDekker
  • 1,584
  • 18
  • 39