Note: If you haven’t already read Part 1, which covers the Gon gem in detail, you can see it here. In this post, I’ll cover the .typeahead JavaScript method.
The How-To (cont.)
-
Typeahead.js depends on having a source of data available. In fact, Twitter’s “basic” typeahead example includes
-
Add the gem:
gem 'twitter-typeahead-rails'. -
Add
//= require twitter/typeaheadto the application.js manifest. -
Determine the css selector for the input on which you want to implement typeahead. In my case, I added a class of “typeahead” to my targeted text field as follows:
(form.html.erb) download 1 2 3
<!-- ...preceding html/erb... --> <%= text_field_tag :name_or_email, nil, placeholder: "To: name or email", class: "typeahead" %> <!-- ... --> -
In whichever JavaScript file you’ve made the dataset available, add
$('.typeahead').typeahead(). Replace “.typeahead” with whatever CSS selector you’re using (see previous step). You now have the entire structure into which you can try the various typeahead.js examples. - I started with the basics, copying line 1-23 above my typeahead method, and everything withing the curly braces from line 37-44 into my typeahead method. Make sure to change the example’s default variable (“states” in the basic example, “best-pictures” in the custom templates example) to whatever variable you assigned using Gon. Depending on how your Rails app is structured–particularly what your asset pipeline looks like–this may be all you need.
-
I had conflicting stylesheets and JavaScript files, plus I wanted more flexibility creating templates for the typeahead, so I implemented the custom templates example. Full code for what I describe is below.
To begin, I added the templates (lines 28-40). The “empty” template worked easily–the code copied from Twitter’s example worked on its own. I had more difficulty with the “suggestion” template, primarily because I didn’t immediately realize that it’s a function, as opposed to the string that the “empty” template was. At this point, I was able to style the template as I liked, even including an image.
Next I had to configure the typeahead to use the pictures connected to each user. Gon and typeahead seem to support a pattern of passing entire objects and calling two or more different attributes (best pictures’ names and years in the custom template example), but I was unable to configure my JavaScript this way. Instead, knowing that my “gravatars” array directly mirrored my “usernames”, I used JavaScript’s
indexOf()method, as seen in line 37. This enabled me to the the index of a given username and find the gravatar url at that index of the gravatars array. Not ideal, but it worked.(typeahead.js) download 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// Twitter Typeahead $(document).ready(function() { var substringMatcher = function(strs) { return function findMatches(q, cb) { var matches, substringRegex; matches = []; substrRegex = new RegExp(q, 'i'); $.each(strs, function(i, str) { if (substrRegex.test(str)) { matches.push({ value: str }); } }); cb(matches); }; }; var gravatars = gon.gravatars; var usernames = gon.usernames; $('.typeahead').typeahead({ hint: true, highlight: true, minLength: 1, }, { name: 'usernames', displayKey: 'value', source: substringMatcher(usernames), templates: { empty: [ '<div class="empty-message">', 'No username matches found. Enter an email instead!', '</div>' ].join('\n'), suggestion: function(username){ return '<div id="user-selection">' + '<p><strong>' + username.value + '</strong></p>' + '<img src="' + gravatars[usernames.indexOf(username.value)] + '"/>' + '</div>' ; } } }); }); -
My final issue came with the highlighting. The
highlight:trueline within the typeahead method indicates that it should work right out of the box, but it did not for me (again, due to conflicting other assets). For this reason, I needed to debug in my JavaScript console, eventually finding that an item selected using typeahead was situated in a div with class of “tt-cursor”. A lot of the default styling was fine with me but, since the highlighting itself did not work, I added the following to my css, thus giving the selected item a background color. “` css styling.css div .tt-cursor { background-color: #16A085; } “` (that selector, “.tt-cursor”, was very important!)
var states, with all 50 states input as strings, directly in the JavaScript file. That’s effectively what I did in the previous post with Gon: I made Rails variables available in JavaScript. I’ll use those same variables here.
2. Typeahead.js
And that concludes my adventures with typeahead. It took some time, but, as I described before, it’s those seemingly minor finishing touches that can end up taking the most time. This exercise was certainly proof of that. But it was worth it to get a working—and good-looking—typeahead form input.