Adam Tuttle

Heavily Customizing a Bootstrap Typeahead

Update 2013-03-20: I've updated most of the sections below with embedded working examples. You can try them out for yourself, and see the source code by clicking the "Source Code" link at the top of each box. These new embedded examples use different sample data than the original post. I went with James Bond actors and movies because it's a small dataset that was easy to work with, rather than the production dataset I was working with in my screenshots when I originally wrote this post. That dataset would have been hard to separate or recreate and doesn't really add anything.

In the future if/when I do embedded examples like these I'll try to make them consistent with the post, but hopefully these still prove useful.

What follows is a (long) chronicle of my adventures customizing a Bootstrap Typeahead control to fit my needs. I can't claim that this is an ordained methodology because the documentation is pretty scant on what exactly you can and can't do with them; but it works and my changes will be used in production very soon.

The most basic typeahead control is simply a filterable list of strings. For example if you want someone to choose their state of residence, you could populate an array with all 50 states and then as the user types they see a list of items that match what they've entered so far:

More complex...

Let's say that you're using this to select a person record from your database instead, and the name doesn't matter so much, it's the person's ID you're after. This is where the other methods come in. You've got to start getting a little bit clever.

Start by adding an additional hidden form field to hold the selected user's id value. I also recommend disabling autocomplete (for modern browsers, at least) so it doesn't compete for screen space with your typeahead:

<input type="text" id="user-input" autocomplete="off" />
<input type="hidden" name="userId" id="userId" value="" />

Then modify your JavaScript:

var users = {};
var userLabels = [];    

$( "#user-input" ).typeahead({
    source: function ( query, process ) {

        //the "process" argument is a callback, expecting an array of values (strings) to display

        //get the data to populate the typeahead (plus some) 
        //from your api, wherever that may be
        $.get( '/api/users/search.json', { q: query }, function ( data ) {

            //reset these containers
            users = {};
            userLabels = [];

            //for each item returned, if the display name is already included 
            //(e.g. multiple "John Smith" records) then add a unique value to the end
            //so that the user can tell them apart. Using underscore.js for a functional approach.  
            _.each( data, function( item, ix, list ){
                if ( _.contains( users, item.label ) ){
                    item.label = item.label + ' #' + item.value;
                }

                //add the label to the display array
                userLabels.push( item.label );

                //also store a mapping to get from label back to ID
                users[ item.label ] = item.value;
            });

            //return the display array
            process( userLabels );
        });
    }
    , updater: function (item) {
        //save the id value into the hidden field   
        $( "#userId" ).val( users[ item ] );

        //return the string you want to go into the textbox (e.g. name)
        return item;
    }
});

The source() function is responsible for taking the input from the text field, using it to get results to display, and passing those results to process(). Since we're going to be converting a string back to an ID once a record is selected, we save a hash-table with the name as the key (and yes, you can have spaces and other odd characters in an object key name) and the ID value as the key value. Then a simple array of names (['John Smith','Jane Smith',...]) is passed to the process() callback.

The updater()function is called when an item is selected, and the selected item's label is passed to it. This is where we convert "John Smith" back to his person ID. We store that person ID into the hidden form field, and then return the string that we want to be placed into the textbox; in this case the name of the person.

Now when the form is submitted, the hidden form field has the selected person's ID, and we can just ignore the name value from the textbox field.

Even More Complex...

One thing that would be nice if it were built into the typeahead control is automatic throttling of calling the source() method on keypress events. If you're hitting an API for the data, best practices would say that you should wait until the user stops typing for some fraction of a second before sending the API request. Otherwise you'll be sending one request per letter pressed.

There's a great method in the Underscore library for throttling events like this: debounce. Debounce waits until it's been N milliseconds since the last time the function was called to invoke it.

So we rewrite our source() method like this:

var users = {};
var userLabels = [];    

$( "#user-input" ).typeahead({
    source: function ( query, process ) {
        searchPeople( query, process );
    }
);

And we wrap its original contents up in a new function named searchPeople:

var searchPeople = _.debounce(function( query, process ){
    $.get( '/api/users/search.json', { q: query }, function ( data ) {

        users = {};
        userLabels = [];

        _.each( data, function( item, ix, list ){
            if ( _.contains( users, item.label ) ){
                item.label = item.label + ' #' + item.value;
            }
            userLabels.push( item.label );
            users[ item.label ] = item.value;
        });
        process( userLabels );
    }
}, 300);

The last line specifies that it should wait 300ms after the last invocation to run. This will cause our AJAX-based typeahead to send less requests to the server, and probably be faster overall as a result.

We Must Go Deeper...

What if you want to do a more advanced search, like allowing input "sm,j" to match partial last names, and partial first names, so that you can filter within the Smiths to show only those whose first name contains a J? Most of the work for this is in the API, but there's one part of Bootstrap worth mentioning here. By default bootstrap will hide any items from the dataset that don't contain an exact match of the textbox contents. So if you search for "sm,j" and both "Smith, John" and "Smith, Jane" are returned, neither will be included in the results; because neither contains the string "sm,j". What you need to do is add the matcher() method, and simply return true. This is safe because the server-side API has already filtered the results for us, so we want to display everything that the server returns:

$( "#user-input" ).typeahead({
    matcher: function () { return true; }
);

Deeper Still

What if a simple string display isn't good enough? Sure, knowing there are two different John Smith's and being able to see the person ID will help you pick the right one; but only if you know the person ID. A better approach would be to show some additional metadata about each person so that it's easier to pick the one you want. If you show their department and the number of years with the company, that should be enough. Heck, if you have headshot photographs available, that would be perfect. But how do you fit all of that in?

Enter the highlighter() method. As documented, this method gives you the opportunity to change the HTML of each item in the list to show how/why it matches. The default implementation bolds the matching section of the string. You can see in the first example above that the "h" in Idaho has been bolded this way. A simple override might bold it and change the color so that it stands out more.

But you can also use this method to get a little crazy. You'd start by including the additional metadata in your API results, of course. Then you've got to save it just like our original hash table for name->id, but more complex:

_.each( data, function ( item, ix, list ) {
    if (_.contains(recruits, item.label)){
        item.label = item.label + ' #' + item.value;
    }
    users[ item.label ] = {
        id: item.personId
        ,name: item.lastname + ', ' + item.firstname
        ,dept: item.dept
        ,photo: item.photoURL
    };
    userLabels.push( item.label );
});

Here, instead of just the ID as the value of each hash key, we store an object with all of the metadata about the person. Then, we use the highlighter() method to return some more useful HTML:

$( "#user-input" ).typeahead({
    highlighter: function(item){
        var p = users[ item ];
        var itm = ''
                 + "<div class='typeahead_wrapper'>"
                 + "<img class='typeahead_photo' src='" + p.photo + "' />"
                 + "<div class='typeahead_labels'>"
                 + "<div class='typeahead_primary'>" + p.name + "</div>"
                 + "<div class='typeahead_secondary'>" + p.dept + "</div>"
                 + "</div>"
                 + "</div>";
        return itm;
    }
});

Then you just have to add some CSS to align things, maybe make the primary text bold and the secondary text a little bit smaller...

.typeahead_wrapper { display: block; height: 30px; }
.typeahead_photo { float: left; max-width: 30px; max-height: 30px; margin-right: 5px; }
.typeahead_labels { float: left; height: 30px; }
.typeahead_primary { font-weight: bold; }
.typeahead_secondary { font-size: .8em; margin-top: -5px; }

And the end result could look something like:

typeahead with multiple lines of text and a photo

Bootrapception

Now let's really get crazy. What if you want to use your typeahead control within a Bootstrap modal? In general, there's nothing wrong with this and it works exactly the same as previously. The only caveat is that the unordered list that's created for your typeahead dropdown is part of the .modal-body section, and therefore if it is longer than the contents of the modal, it hides behind the modal footer and you've got to scroll the contents of the modal to see it.

long typeahead in a modal dialog

You may be fine with this behavior. I wasn't; particularly because when you hit the down arrow key to select a different item from the list, and your selection isn't visible, it appears as if nothing happens. I'm sure that the list-item has a blue background, but it's not visible so it's not helping much. I wanted my typeahead list to expand beyond the body of the modal.

Unfortunately, because of the way Bootstrap modal dialogs are placed, this wasn't a straight CSS fix. The only way I've found to get the UL to display on top of the modal footer is to use position:fixed which requires precise top & left values; but modals are not absolutely positioned. It's not ideal, but it can be done with JavaScript without putting too much strain on the browser.

First I added a class to the div that wraps the label, textbox, and the UL that's generated for the typeahead (the .controls div from my form). Then I added some CSS to force the UL to use position:fixed, and while we're at it, always be the same width as the textbox:

.recruitTypeahead ul {
    width: 350px;
    position: fixed;
}

But as I said, we need the precise top & left values to position it correctly, and this can only be found with JavaScript. So we create a function to calculate the position of any element on the page:

function elPos(element){
    var position = { x:element.offsetLeft, y:element.offsetTop };
    while(element = element.offsetParent){
        position.x += element.offsetLeft;
        position.y += element.offsetTop;
    };
    return position;
}

And then use it to find the position of the textbox. After a little bit of playing with it I decided that the textbox's top + 32 pixels was a good value for the UL's top, and I give them the same left value. (Note that hard coding the value like this comes with its own problems: What if the user's browser has the font size cranked up? But it's close enough to get us started. If you want to take it further, use the object's height, plus a small amount of padding.)

var fixPersonTypeaheadPos = function(){
    var box = $("#user-input")[0];
    var newPos = elPos(box);
    $(box).parent().find("ul.typeahead").css({top: newPos.y+32, left: newPos.x});
};

It seems like Bootstrap updates the position of the UL (or more likely deletes and recreates it), every time the typeahead content changes, so you've got to call this method after the content has been supplied, every time it changes. Unfortunately Bootstrap doesn't expose an event for this--but we can piggyback on an existing event.

You could use either the highlighter() method or the matcher() method. I chose matcher() because my matcher implementation is far less complex, so it will run more rapidly. But still, it ends up calling the method once for each item in the dropdown, which would be overkill for our purposes. Our first thought should be to use debounce to prevent unnecessary invocations, and that's not wrong, but this is also a good opportunity to use debounce's immediate argument, so that the re-positioning is done as quickly as possible but subsequent rapid calls to the method do nothing:

$( "#user-input" ).typeahead({
    matcher: function(item){
        fixPersonTypeaheadPos();
        return true;
    }
});

var fixPersonTypeaheadPos = _.debounce(function(){
    var box = $("#user-input")[0];
    var newPos = elPos(box);
    $(box).parent().find("ul.typeahead").css({top: newPos.y+32, left: newPos.x});
}
, 10, true);

This runs once immediately, and then won't execute again until it's been at least 10ms between invocations; and since each iteration of the function is simply returning true, it should only be 1 or 2ms between invocations, and so only the first invocation causes the function to execute.

Put it all together and we've achieved the desired result: the typeahead dropdown menu expands on top of the modal footer and is completely visible.

long typeahead in a modal dialog

70 responses:

Alex

Alex

Superb post! Just one thing, I was able to use typeahead in a modal easily by adding ".typeahead { z-index: 1051; }" in my CSS.
Mahbub

Mahbub

Can you put your source code in Github ?
Adam

Adam

Alex, I would swear I tried that, but it wouldn't be the first time I messed something that simple up.

Mahbub, I'll see if I can separate it out from what I'm working on and toss it out there. It'll take some time, though.
Louie

Louie

Amazing article! I'm still a jquery/bootstrap beginner but I learned a great amount studying what you've done. Definitely going to use a lot of this material in the new project I'm working on, especially the underscore library throttling. This is great Thank you!
Tony Dew

Tony Dew

Thank you for the update! The code samples are really helpful.
Alec E

Alec E

Outstanding article! Level of detail goes above and beyond what I would expect from, well, pretty much anyone! Props, for sure.

Question out of left field: I'm working on a project that I'm already using Bootstrap extensively for and need to have a typeahead function like this. However I need it to dump the results from the search into a DIV (specifically, a list of checkboxes with labels) and not a dropdown. Any thoughts on how one would accomplish this?

Thanks again for all the info!
Adam

Adam

Hi Alec, It sounds like you might be trying to do too much with a typeahead. It's possible to do what you're asking but without knowing more I can't say whether or not you should pursue another avenue. Basically I would draw the line at the dropdown contents: If you don't want your results displayed in a dropdown below the text input, a typeahead control is not what you should use. In that case, just use a textbox and handle the keypress events manually, and fill your div with whatever you like.
PJ

PJ

huge thanks for this!

fyi: regarding section "More Complex", the line:
data = $.parseJSON(data);

is in the web page, while not in the source code.

lol, lost some hair troubleshooting that one. :)
Adam

Adam

Hi PJ - you're right. I'm not sure when things diverged, but at some point I realized that the parseJSON call was unnecessary. I'll remove them from the code samples now.
Arif Majid

Arif Majid

Excellent
have been using jquery autocomplete in bootstrap themes ... now finally something great to work with.
Thanks
PJ

PJ

Hummm.
Interesting you should say that.
I'm returning data from an mvc jsonResult.

For me:
Without the parseJSON, as I stepped through the method, each iteration had only on character of the data string, and things didn't work. It stuck at the process() line per firebug.

With parseJSON, as I stepped through, each iteration had the full Bond name, and worked perfectly.

So maybe it's an implementation situation with my application.
All I know, it's working now with parseJSON in the code.

Thanks again
PJ

PJ

Re: "I'll remove them from the code samples now. "

May I suggest that you keep it in the code, but commented out.
Include a note like "This may be necessary for proper execution."

This way both situations are covered.
Adam

Adam

PJ, I think it has either to do with your version of jquery or being sure you set the expected return data type in your Ajax request.
Will

Will

Wow, it's like you wrote this because you knew I was going to need it today.
daniel

daniel

Greatest post about Typeahead i ever read. Helped me much. Tks
Manifiestate.net

Manifiestate.net

Grande!
We will use in our future version the extended "highlighter" with image you've posted.
Javier

Javier

wowww, this is awesome!!! thank's a lot!
Brig Lamroeaux

Brig Lamroeaux

Great walk through. This is exactly what I needed.
Yuri

Yuri

Thanks for the great article, Adam! It helped me a lot!
Nevertheless, there is still an annoying and disappointing thing I've been struggle for couple of days with no luck.
Imagine that a user types in something without selecting an item from the list. (Actually, you can try it on the second or third form on this page). Let's say he types "Timothy Dalton", then clicks outside the typeahead field (imaginary submit button for example or other field in the form). In this case the hidden field value remains EMPTY :( Or, try to input any other correct name (Daniel Craig), select it, hidden field is set to actor's id = 8, then you change your mind, erase Craig and input somebody else's name or any other "bla-bla".. Click outside or "submit". Id remains unchanged and it's still Craig's 8.
It's a pity but it makes the pretty hidden field id passing solution useless if we're going to save it into DB for example.

I would greatly appreciate any suggestions about how to get this great typeahead feature to work properly with item id passing.
Adam

Adam

Hi Yuri, I'm glad you're finding this post useful.

I think the problem you describe is just a shortcoming of the way typeaheads work. This flaw is inherent even in the most basic implementation where everything is hard-coded. But of course there's always a way around it.

For starters, you could update the highlighter or source method (no point in doing both) to clear out the hidden form field, because anything that triggers them is essentially a further search. You could also always update the hidden form field to be the first value in the search results; which is *sort of* what's implied by clicking elsewhere on the page to make the typeahead go away, since the first item is highlighted by default.

My last idea is to build on the first: clear the hidden field in the source function, and then on blur of the text field, if the hidden field is still empty, also clear the text from the typeahead, to give the user feedback that they haven't actually selected anything.
Jashk

Jashk

thanks a lot, very useful :D
Paul Stocks

Paul Stocks

Fabulous! very helpful.
Is it possible to trigger the Typeahead from the updater?
I'd like to 'page' long lists with a '-- more --' at the bottom.
I can reset the original query but can't trigger a change event.

P:)
Kevin Jensen

Kevin Jensen

Wonderful post! Looking forward to playing with this one.
Matt Bram

Matt Bram

Great Post!!!

I've been trying to figure out the highlighter function for a couple of hours and I immediately saw what I was doing wrong. Thanks!
Derek Chen

Derek Chen

Amazing post.
I learn a lot from your article.
Thanks so much
Logesh

Logesh

How can i pass the link once the list is selected.in brief - if i select a list it should navigate me to respective list page or view.could you help me in that
Logesh

Logesh

Forgot to say in my previous comment,
pal you article is nice work,
Adam

Adam

Logesh, you can use the "updater" function to redirect on selection. Just do a "window.location.href = '...';" instead of updating a hidden form field, based on my example listed under "More complex..."
Logesh

Logesh

Thank's Adam,thank's for the reply and great work pal,,
Kash

Kash

I am doing similar thing in my application but facing memory leak as the backbone collection that holds the old result is not garbage collected...So the browser memory keeps increasing after each search...

any thoughts on this please?
Adam

Adam

Kash,

I assume you're referring to the way I use a variable to hold all of the item metadata between the source/highlighter/updater calls? I can certainly see how that would be a problem in a single page app where the whole page never flushes.

I won't claim to be an expert on JS memory management, but I suspect that if, in your updater function, after doing everything that needs to be done with the metadata, if you run "delete varname;" it should help. Maybe attach it to something other than the window object (which is the default) to make it easier/clearer to reference.
Kash

Kash

Thanks Adam.

In my case I am using Backbone collection to hold result items and the old data never gets garbage collected. Also as you mentioned in a single page app where the whole page never flushes this is a an issue.
Konst

Konst

Nice post, the last fix can be done easier.
.modal-body
{
position: static;
max-height: 400px;
padding: 15px;
overflow-y: hidden;
}
Laercio

Laercio

Obrigado, esse post me ajudou muito.
Adam

Adam

Glad I could help, Laercio. :)
Jay

Jay

Very nice article, you made my day with this. Just a small suggestion, it would add more value to the article if you can add some more info for other attributes in Typeahead like updater().
Adam

Adam

Jay, I did cover updater, but only briefly. There's not much to it... It's called after an item is selected from the menu and passed the same value that's passed to the highlighter function (e.g. the string that you push into the "process" callback from the source method). You can do anything you want with it, or with anything else. It's just a function that's called. If you return a string, that string will be placed into the typeahead textbox.
Mujahid

Mujahid

A very useful tutorial. Thanks a lot. I'm trying to create a filterable list item like in the following link

http://jquerymobile.com/demos/1.2.1/docs/lists/lists-inset.html

I found that the functionality is not directly available in the bootstrap and then I found your tutorial. It gave me hope at least I can reach to some extent. But what I really wanted to do is, there should be checkboxes for each list items and user can be able to check multiple checkboxes. It doesn't have to be shown in the filter box though. Any suggestions welcome as I want to implement this on mobile, I dont wanna go with jqmobile as its too heavy and hard to use with other libraries.

Thanks
Adam

Adam

Mujahid, I think you're trying to do too much with a Typeahead. It's not meant for the type of behavior you're describing, so it's going to be difficult to implement and may never work exactly as you're hoping. I'd keep looking for something else.
Mujahid

Mujahid

Hi Adam, Thanks a lot for your prompt reply. Yes, I know its a very complex task, but I don't wanna use jqmobile as mostly I need only this functionality to the project. I'm also looking for some other light-weight solutions available with the same type of functionality in the jqmobile.
Mina Magdy

Mina Magdy

Hi Admin,
I wish if you can help me, i made an "input-append btn-group" for "dropdown" and i want a js to can show all possible results can find from li when user writing in current time. in this example if user type "e" can show him "edit and delete" to choose one of them.
<code>
         <div class="input-append btn-group">
            <input class="span2" id="appendedInputButton" size="16" type="text">
            <a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
               <span class="caret"></span>
            </a>
            <ul class="dropdown-menu">
               <li><a href="#"><i class="icon-pencil"></i> Edit</a></li>
               <li><a href="#"><i class="icon-trash"></i> Delete</a></li>
               <li><a href="#"><i class="icon-ban-circle"></i> Ban</a></li>
            </ul>
         </div>
<script>

$(function(){
$(".dropdown-menu li a").click(function(){
$("#appendedInputButton, .btn:first-child").text($(this).text());
$("#appendedInputButton, .btn:first-child").val($(this).text());
});
});
</script>

</code>
how can done this ?
KCS

KCS

Hi, when I add a blur or change binding to a bootstrap typeahead, then 'clicking' on an item in the drop down list portion does not activate 'updater'. Pressing enter is ok. Take off the binding, click then works. I need to bind blur or change so I can test id the user has entered a non-matching value. Any ideas? Thanks.
Matthias

Matthias

Great work, thank you - but it will not run on my space.
I got the message "Uncaught TypeError: Cannot call method 'toLowerCase' of undefined" when I run exact the same code with James Bond on my playground. I can't find whats happend. Can you perhaps, Adam?

Thanks.
Matthias

Matthias

Oh, I got it:
It was necessary to set the typeDate at the ajax-request to json like this: {typeData: 'json'}
Ones again: Thanks for your Tutorial, Adam.

Matthias
Thuurke

Thuurke

I have a php file that generates a json encoded array from mysql. When I open the php file in a browser and I copy the generated array to the bonds.json file then the names are shown. When I replace bonds.json in the code by filename.php it won't work. What do I have to change?
url: 'bonds.json' gets url: 'generatejsonarray.php'
Budhram

Budhram

Best blog on typeahead.js so far.
musaid

musaid

just what i need. great work :)
Romnel Pateres

Romnel Pateres

Bogo ka oy!
tony

tony

Hello sir ,
i like your amasing code
how can i replace the bonds.json by i exemple.php where php file collect the datafrom mysql database
please i need help thanks alot
Ryan M

Ryan M

There doesn't seem to be any query strings being sent to the JSON file. It's just loading the raw file & parsing that.

I'm using the code from plunker, works fine to load everything from the raw JSON file. But without the parm's of the input box being sent it's not really a live search.

Everything else works great tho.
Adam

Adam

Ryan, you're correct. Bootstrap 2's typeahead feature offers client-side filtering, which these examples make use of. You could easily modify the examples to send query string parameters and filter the data server-side -- but that would greatly complicate the examples, which is why I didn't show that.
Nikki

Nikki

I find this very useful. Just a thought, If I put several typeaheads in my page, How can I differentiate the id retrieved by the first typeahead to the second one or to the 3rd one?
Will

Will

Hi Adam

very interesting article, thank you.
I have one issue with this component though, maybe others have come across it too.

The component is attached like this on an input, in my $(function()) :
$('#tagsInput').typeahead({ source: ["Alabama","Alaska","Arizona"] });

I'd like to programmatically add items to the elements list, so I tried in the console :
$('#tagsInput').typeahead({ source: ["Alabama","Alaska","Arizona","Whatever"] });
which, I thought, would dynamically update the list, but it doens't.

So I tried to unbind all events off the input, as I didn't find any destroy event for typeahead():
$('#tagsInput').off()

Of course it works, but then I can't attach the typehead behaviour anymore, any
$('#tagsInput').typeahead({ source: ["Alabama","Alaska","Arizona"] });
remains without effect ...

Any clue on a way to change the list of elements dynamically ?
Thank's for reading me :)
Adam

Adam

Will, just use a variable reference of your array data and change the array as you see fit:

states = ["Alabama","Alaska","Arizona"];

$(function(){
$('#tagsInput').typeahead({ source: states });
});

states.push('Arkansas');
Will

Will

Perfect !
Of course, once you know it, it seems obvious ;)

Thank you very much for your fast answer.
Miguel

Miguel

I'm new to bootstrap and this example is just what I needed. It worked fine for me using bootstrap-typeahead version 2.3.1.

My first attempt was using the library provided in http://twitter.github.io/typeahead.js/ which is version 0.9.3. But I realized that this version does include anymore 'source' and 'updater' functions. So I'm guessing typeahead forked away from bootstrap because twitter-bootstrap latest version 3.0.2 does not include any references to typeahead.

Wondering if someone has tried implementing this examples with typeahead.js v0.9.3?

Thanks for the post.
Jermanis

Jermanis

Same question as Miguel.

Does anyone know the update for 'source' being removed in typeahead?

I've tried remote and local, but that results in another error "Uncaught TypeError: Cannot call method 'replace' of undefined "
Guilherme

Guilherme

Same question as Miguel...
oliver

oliver

Take care that the Document Header of the JSON File is application/json
Naveen

Naveen

Great article. Looks I am missing the source() function.
I have Typeahead which is working properly when textbox (id="inputfield") is getting value when typing. However when I am calling the same function from other function which is passing the input character one by one it is not working.

http://stackoverflow.com/questions/23225823/typeahead-autocomplete-call-from-other-function

Kindly help.
vectDeeld

vectDeeld

nfkovfppsi [url=http://www.travelloop.es/controlremoto/phpinfo.asp?f=90]Zapatillas Free Run 2[/url] yanknibvzk [url=http://www.plazadelaguaydelaluz.es/modules/main/configuration.asp?max=110]Nike Air Max Precio España[/url] uftndzdjct [url=http://www.leonardopolo.net/seminar/user.asp?rb=97]Lentes Para El Sol Ray Ban[/url] orcdpjwxue [url=http://www.leonardopolo.net/seminar/user.asp?rb=31]Cristal Ray Ban[/url] mpesaekyul [url=http://www.galtvalles.com/extras/assitant.asp?a=81]Modelos Abercrombie Call Me Maybe[/url] xuisyhlntd [url=http://www.vatech.com.es/light/prcenter/login.asp?a=847]Zapatillas Adidas Casual[/url] qqpbkadvjg [url=http://www.leonardopolo.net/seminar/user.asp?rb=244]Ray Ban Imitaciones[/url] dgmiznrtjf [url=http://www.vatech.com.es/light/prcenter/login.asp?a=817]Zapatillas Imitacion Adidas[/url] flcokgofja [url=http://www.vatech.com.es/light/prcenter/login.asp?a=296]Adidas Nba Jerseys[/url] syjkqvxess [url=http://www.plp-spain.com/docu/diashow.asp?h=42]Significado De Hollister[/url]
Mike

Mike

Hi Adam,

Very nice tutorial. I was wondering if you have an updated version for Bootstrap 3 with the new typeahead.js using ColdFusion to get data from a sql database.

Thanks
Mike
Philippe

Philippe

Thank you for your time, it was very useful.
One thing, when I used the _.debounce() function, if I entered text and got result, when I delete everything in the text field it is doing an 'extra' request with the keyword from last request, I just removed the debounce() and it worked as expected.
Cheers
Erik

Erik

Hey man, top job.. thanks!! This really is the *only* solution.. I upgraded to 0.10.2 where they seem to have ditched the matcher and highlighter functions..

So in the end I found it easier to wrap the thing in a container and on 'typeahead:opened' position the container fixed with top/left/width exactly on the original spot.. and then remove the element styles on 'typeahead:closed'..

Cheers,
Erik
Erik

Erik

For Miguel:

var scope = this;
var target = scope.$el.closest('div.type-ahead-container');
var parent = target.parent();

function elPos(element){
var position = { x:element.offsetLeft, y:element.offsetTop };
while(element = element.offsetParent){
position.x += element.offsetLeft;
position.y += element.offsetTop;
};
return position;
}

var p = _.debounce(function position() {
var newPos = elPos(parent);
parent.css('height', parent.height());
target.css({position: 'fixed', width: parent.width() + 'px', top: newPos.y-34, left: newPos.x});
}, 10, true);

scope.$el.typeahead(null, {
name: 'input-type-ahead',
minLength: 0,
source: list.ttAdapter ? list.ttAdapter() : list,
template: Handlebars.compile(this.tmpl),
engine: Handlebars
}).on('typeahead:opened', function(event) {
p(); // ES: Fixed position exactly on the original spot...
}).on('change', function(event) {
// ES: Make sure the change event fires before the selected event...
scope.log('typeahead:change', 4);
selected = false; // ES: Assume non is selected
}).on('typeahead:closed', function(event) {
target.css({ 'position' : '', 'top' : '', 'left' : '', 'width' : '' });
parent.css('height', '');
scope.log('typeahead:closed', 4);
scope.setTimeout(function() {
// ES: The setTimeout postpones the function until AFTER the typeahead:selected event
if (!selected) {
scope.log('typeahead:change:processQueue', 4);
scope.QC.processQueue(true);
}
}, 0);
}).on('typeahead:selected', function(event, data) {
event.stopImmediatePropagation();
scope.log('typeahead:selected', 4);
// ES: Set selected to true so our postponed function will not fire
selected = true;
// ES: Instead processQueue will be skipping the waiting items by default
scope.bubble('runTrigger', 'typeahead-selected', data);
});
James Wu

James Wu

Hi,

I am puzzled how typeahead only shows the matched suggestion items... In the source function, after reading json data, loop each items, and push EVERY item:
userLabels.push( item.label );

I would think all suggestion items show up; but only the matched ones. Where is the matching taking place? Shouldn't the code be:
if (item.label.indexOf(query) > -1) { userLabels.push( item.label );
}

Someone please explain. Thanks
Arran Maclean

Arran Maclean

Thank for all the great post.

It's really helped me,

Cheers
Noodles

Noodles

I've been using this example for a little over a year and I've only come across this problem now.

I'm trying to clear the typeahead input box, but the few things I've tried doesn't seem to work.

I tried clear the input value after selecting an option from the list in a few places, even after losing focus on the input.

Would be great if I could get help on this.
Neely

Neely

Hi,

Do you also encounter that when using in Internet Explore (I tried mine in IE10), the textbox will show a clearing “x” when inputting the text value.

And then the input value will be retained also even if we click the clear “x”. Do you have any suggestion on how to overcome this?

Thanks.
Neely

Neely

Hi,

Do you also encounter that when using in Internet Explore (I tried mine in IE10), the textbox will show a clearing “x” when inputting the text value.

And then the input value will be retained also even if we click the clear “x”. Do you have any suggestion on how to overcome this?

Thanks.

Your comment:

Leave this field empty: