I\'m using Bootstrap 2.1.1 and jQuery 1.8.1 and trying to use Typeahead\'s functionality.
I try to display a label and use an id li
As of version 0.10.1 of Twitter Typeahead (https://github.com/twitter/typeahead.js), Id / Label is supported natively:
$('input[name=address]').typeahead({
hint: false
}, {
source: function (query, cb) {
$.ajax({
url: '/api/addresses?q=' + encodeURIComponent(query),
dataType: 'json',
cache: false,
type: 'GET',
success: function (response, textStatus, jqXHR) {
cb(response.data);
},
error: function (jqXHR, textStatus, errorThrown) {
}
});
},
name: 'addresses',
displayKey: 'text'
}).on('typeahead:selected', function (e, suggestion, name) {
window.location.href = '/' + suggestion.id;
});
If the example above, I'm passing an array of objects to the source callback (cb). By specifying displayKey: 'text', I'm telling the library to use the 'text' property for the auto-suggest. When the 'typeahead:select' callback is called, the second argument passed in (suggestion) contains the object that was selected.
The problem I have seen with some of these solutions, is that the source
function is called repeatedly on every keyup event of the input box. Meaning, the arrays are being built and looped over on every keyup event.
This is not necessary. Using a closure, you can process the data only once, and maintain a reference to it from within the source
function. In addition, the following solution solves the global namespace problem of @Gerbus's solution, and also allows you to play with the array of data once the user has selected something (for example, removing that item from the list).
// Setup the auto-complete box of users
var setupUserAcUi = function(data) {
var objects = [];
var map = {};
$.each(data, function(i, object) {
map[object.name] = object;
objects.push(object.name);
});
// The declaration of the source and updater functions, and the fact they
// are referencing variables outside their scope, creates a closure
$("#splitter-findusers").typeahead({
source: function(query, process) {
process(objects);
},
updater: function(item) {
var mapItem = map[item];
objects.splice( $.inArray(item, objects), 1 ); // Remove from list
// Perform any other actions
}
});
};
// `data` can be an array that you define,
// or you could pass `setupUserAcUi` as the callback to a jQuery.ajax() call
// (which is actually how I am using it) which returns an array
setupUserAcUi(data);
The selected answer is a bit of a hack. I was looking for the same thing, and this approach works beautifully:
https://github.com/twbs/bootstrap/pull/3682
It keeps two arrays, one for the name that typeahead shows, and one for the object from which the name is extracted. When one of the options is selected, it uses the name to find the object from whence it came.
I've been struggling with this problem myself, here is the solution I came up with, for data of the type:
[{'id':an_id, 'name':a_name}]
Was:
$("#memberSearch").typeahead({
source: function (query, process) {
var $this = this //get a reference to the typeahead object
return $.get('/getSwimmerListJSON',function(data){
var options = [];
$this["map"] = {}; //replace any existing map attr with an empty object
$.each(data,function (i,val){
options.push(val.name);
$this.map[val.name] = val.id; //keep reference from name -> id
});
return process(options);
});
},
updater: function (item) {
console.log(this.map[item],item); //access it here
}
});