Twitter Boostrap Typeahead Tutorial

Twitter Bootstrap provides an autocomplete/typeahead component which is very easy to use, but is a bit tricky to use (in my humble opinion) when you are working with anything more than a simple String array as your source of autocomplete options.

Say for example you want to allow users to search your server-based database of products based on the product name. The user types in the name of the product and typeahead goes off and makes an asynchronous request to the sever to query the database and returns a list of products. In the typeahead widget you want to show the user the list of potential product names, but when they select one of the options, you want to able to populate the display with the product price, SKU, description, etc. and of course you need the ID from the server so you can manage communications with the server, say for a purchase.

For starters though, let’s go over the basics of how typeahead works. The following example has 3 potential product names:

  • Deluxe Bicycle
  • Super Deluxe Trampoline
  • Super Duper Scooter

Type in whatever partial name you want and you’ll see the appropriate typeahead options.

The code for that is fairly staightforward:

It’s simply an input tag with data-provide=”typeahead” to indicate that we want typeahead on the input tag, and then data-source specifies an array of strings.

Let’s step things up a bit and move the array from being declared inline with the element, to being dynamically populated in Javascript:

Visually, this behaves identically. Try out the following text input by typing a substring of one of the product names:

But as you’ll see in the source, here we do not specify data-source in the input element declaration. Instead we call the typeahead() method on the input element and pass in the source option as a function which returns the string array.

If you wanted to retrieve the list of products from the server, in your source function override you would make your AJAX call, and then in the asynchronous response you would generate the string array and call process(), passing in the string array.

I also found that there was a bug in some browsers with the typeahead component when trying to select one of the typeahead options with the mouse. This is a known issue. Sometimes mouse selection doesn’t work. Rather than change the bootstrap-typeahead.js file, I’ve overwritten the typeahead blur() method to give it a slightly longer than normal delay.

Besides the source option, you can also specify a highlighter() function that specifies how each possible autocomplete option is displayed, and an updater() function that can execute some code when the user selects an item. In the following I’ve modified the display of each item using the highlighter() override, and I print out the selected item to the console in the overridden updater() method:

Objects

Now, the moment you’ve been waiting for. Well, almost. If you’ve stuck around this far, you’re not interested simply in an array of strings. Your data is more likely an array of objects. The following input should behave identically to the previous one, only this time we have an array of product objects. Each product object contains an id, a name and a price.

Here’s the code for that:

The main difference here, other than the declaration of the products array is in the source override. We generate an array of strings based off the name property of each product object. If you wanted to expand this example to retrieve your list of objects from the server, in your source function override you would make your AJAX call, and call process() on the results from the asynchronous response.

But that’s not really what I want. I want to display the name and price of each object in the list of typeahead options. And I want to display the selected item with all of its details.

What we need to do first is instead of having the source function return an array of strings, we’re going to have it return an array of product ids. Since the ids are numbers, and process() is expecting an array of strings, we convert each id to a string first.

The typeahead component is then going to call matcher() for every item, to make sure that, by default the original query string is a substring of the item. Since our item is simply the product id, that’s not going to work, so we need to override that. For simplicity sake, I just always return true, but you could use the product id to get the product from the list of products, and then check that product’s name against the query if you wanted.

Next, in the highlighter() method, I use Underscore’s find() method to find the product in the array of products based on the product id, and then display a combination of the product name and price.

Finally, in the updater() method, which is called when an item is selected, I find the selected product just as we did in highlighter(), but now I call that.setSelectedProduct() with the product name. that is defined using closure outside of the typeahead() call on the element, as is setSelectedProduct(). You could have setSelectedProduct’s functionality right in updater() but I thought it might be nice to pull it out of the updater() code to make it a little more reusable.

Last but not least updater() returns the product name, so that is what you are left with in the input element.

Here’s the working example:

and here is the full and final source:

Hopefully this should all make implementing real-world typeahead a little easier.

Update June 4, 2013:  The Twitter Bootstrap team have announced that for v3, they are going to be moving to Twitter’s typeahead.js instead of the current Twitter Bootstrap Typeahead component.  I’ve written an article on how you can use typeahead.js right now with Twitter Bootstrap.
Tagged , , , . Bookmark the permalink.

26 Responses to Twitter Boostrap Typeahead Tutorial

  1. Nick Karnik says:

    Thanks for this fantastic tutorial! I checked out the other project and it’s not being maintained anymore. It has links to three others, but I don’t see an immediate need to switch.

  2. Tony Dew says:

    Thank you for the post, however, there might be a little bit easier way to solve the “missed mouse click” bug without introducing a delay.


    $('.typeahead').live('mousedown', function(e) {
    e.preventDefault();
    });

    It’s not my solution, I found it here:

    https://github.com/twitter/bootstrap/issues/4018#issuecomment-12299398

  3. Ibrahim Awwal says:

    Hmm, is it just me or is the last example broken? Regardless, great tutorial, the official documentation is a bit on the sparse side…

  4. Michel fonteneau says:

    Hello Great tuto!
    I am facing an issue I change all my french character to the correspondant in ascii, but when I’m typing a word as soon as I enter the foreign letter it passby the word. like for “Champs-Élysées” (code Champs-Élysées int the return array) at “É” it remove the choice in the selected list.

  5. Heiko says:

    Hallo Alan,
    how can i jump to a other html site when i click on a word.
    Same like on google…???????
    Greetings

    • agreenblatt says:

      Heiko -

      When you do a search in Google, the typeahead helps you choose words to search on, but then ultimately it updates the current page with result links, any of which you can click on to jump to another site.
      Similarly, if you look in the post above, I specify an updater in the typeahead options which is called when the user selects a word. Currently, I have this set to write out the selected item to the console. You could instead use this function to either directly jump to another site, or to update the display and include some links to other sites.

      • Logesh says:

        Hi agreenblatt, could you give a sample code, it might be quite useful for learners like me,, thank oyu

        • agreenblatt says:

          Logesh – What code are you looking for? This post is filled with code.

          • Logesh says:

            Hi agreenblatt , i am looking for the code to pass the link through the list items,am using jason for fetching the content from database. could you help me out.
            thank’s for your reply..

          • agreenblatt says:

            Logesh, it sounds like you’ve already managed to get the JSON response, and are just trying to figure out how to create the proper links. If so, presuming your JSON objects have for instance product names & URLs, something like:

            [
            {name: "Deluxe Bicycle", price: 499.98, url: "http://foo.com/products/1"},
            {name: "Super Deluxe Trampoline", price: 134.99, url: "http://foo.com/products/2"},
            {name: "Super Duper Scooter", price: 49.95, url: "http://foo.com/products/3"}
            ]

            then in setSelectedProduct() you could do something like:

            $('#product').html("Purchase: <a href='" + product.url + "'>" + product.name + " ($" + product.price + ")").show();

  6. Pingback: Twitter Bootstrap typeahead.js with underscore.js Templating Tutorial - Alan Greenblatt

  7. Logesh says:

    Thank’s agreenblatt,, from your reply got an idea and I have linked using the code below,,
    updater: function (item)
    {
    var index=tasks.indexOf(item);
    if(index!=-1)
    {
    window.location.href= lnk[index];
    }
    },

  8. Logesh says:

    if(isset($data) && !empty($data))
    {
    echo “[";
    for($i=0;$iconfig>item("base_url")."tasks/view/".$data[$i]['category_id'].”/”.$data[$i]['id'].”/home\””;
    if($i == count($data)-1)
    echo “}”;
    else
    echo “},”;
    }
    echo ‘]’;

  9. Awesome tutorial. I was searching for this code. Thanks :)

  10. Clint Nick says:

    I’ve been trying to figure out how to make this work with prefetch. I like that it drops down more information about the product for the user to make a better informed choice before selecting the data.

    I’m sure it’s just a syntax thing but it has me stumped. Any suggestions?

  11. Oleg says:

    Thanks for tutorial.
    In my application i need that when I click outside of the popup menu or click esc – in input field automatically inserts the first value of the items found.
    Can you help me?

  12. Hello Alan ,

    I am trying to use your very first example but unable to use that code provided.

    Do I need to use the jquery , bootstrap-typeahead of specific version that would have used here ??

    • agreenblatt says:

      Chitrank,

      Start with exactly what I have here, make sure it all works, and then you can try different versions. If you do that and it still doesn’t work, let me know what the problem is and perhaps I can point you in the right direction.

  13. DJAffinis says:

    Thanks for this awesome tutorial. I noticed you put _.map instead of $.map which causes a syntax error. Hope this helps.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>