I am playing around with Typeahead and I am trying to figure out if there is a way to display Pictures and Labels in the search query as well? Something like how Twitter does when we try to mention users on Tweets.
5 Answers
After doing some research and pulling almost all my hair out, I finally figured out how to add Fullname, image and username to a typeahead like twitter.
Lets say this is the following structure of each object for your source,
{{ friend.id }}#{{ friend.username }}#{{ friend.imgurl }}#{{ friend.fullname }}
Then all you have to do is write a nice Highlighter, something like this
highlighter: function(item) {
var parts = item.split('#'),
html = '<div class="typeahead">';
html += '<div class="media"><a class="pull-left" href="#"><img src='+parts[2]+' /></a>'
html += '<div class="media-body">';
html += '<p class="media-heading">'+parts[3]+' (@'+parts[1]+')'+'</p>';
html += '</div>';
html += '</div>';
return html;
},
This will easily add the Picture, Full name and Username in Typeahead.

- 267,341
- 46
- 444
- 390

- 2,728
- 10
- 43
- 73
-
I think you're missing a closing div here. But otherwise, works great. – Braydon Batungbacal Aug 20 '15 at 21:30
highlighter is not working anymore.
Use templates, example:
var my_friends = [
{name: "John", picture: "http://..."}
,{name: "Mel", picture: "http://..."}
];
var friends = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: my_friends
});
friends.initialize();
$('#friend_name').typeahead(
{
hint: true,
highlight: true,
minLength: 1,
},
{
name: 'friends',
displayKey: 'name',
source: friends.ttAdapter(),
templates: {
empty: 'not found', //optional
suggestion: function(el){return '<img src="'+el.picture+'" />'+el.name}
}
}
);
Source: https://gist.github.com/jharding/9458780#file-custom-templates-js

- 144
- 1
- 8
You will likely find it easier/better to use http://ivaynberg.github.com/select2/ instead of trying to customise the default rubbish Bootstrap one!
If you search for Templating on that page, you'll find it - it looks like this:

- 71,795
- 44
- 182
- 241
-
can I still use my custom matcher and updater functions with it? I am actually trying to implement the @ triggered typeahead in a textarea, like Twitter. – Jonathan Jan 05 '13 at 07:23
-
It has it's own functions, but I suspect the syntax will be similar enough. Select2 can act as a typeahead rather than a select box if you pull in the stuff via ajax. To be honest I gave up on the bootstrap one pretty quick as I wanted typeahead across 20-30,000 items so needed to do the filtering on server instead of client. – Rich Bradshaw Jan 05 '13 at 09:35
-
lol okay. Well I finally figured out how to add the extra stuff for Bootstrap's Typeahead as well. So I think I am going to stick with that – Jonathan Jan 05 '13 at 12:49
-
-
2Honest question, why do you call it rubbish? `"...default rubbish Bootstrap..."` – user May 02 '14 at 10:32
You can try to use the following customized code for rendering images containing with the JSON schema.
Please follow the fiddle link here for implementation and testing.
The typeahead looks like:
$(".typeahead").typeahead({
source: function (query, process) {
//here we pass the query (search) and process callback arguments to the throttled function
throttledRequest(query, process);
},
highlighter: function (item) {
var test = testObjs[item];
return '<div class="test">' + '<img src="' + test.photo + '" />' + '<br/><strong>' + test.name + '</strong>' + '</div>';
},
updater: function (selectedName) {
//note that the "selectedName" has nothing to do with the markup provided
//by the highlighter function. It corresponds to the array of names
//that we sent from the source function.
//save the id value into the hidden field
$("#testId").val(testObjs[selectedName].id);
//return the string you want to go into the textbox (the name)
return selectedName;
}
});

- 604
- 1
- 9
- 18
typeahead.initialize();
var typeahead = {
typeaheadInit: function() {
var jsonData = [{
'id': 1,
'name': 'Parajanov Museum',
'image': 'img/1.png'
}, {
'id': 2,
'name': 'Parajanov’s Movie',
'image': 'img/2.png'
}, {
'id': 3,
'name': 'S Parajanov’s about his series of Giocondas',
'image': 'img/3.png'
}, {
'id': 4,
'name': 'S Parajanov’s about the colore of pomegranate',
'image': 'img/4.png'
}, {
'id': 5,
'name': 'George Michael',
'image': 'img/5.png'
}];
var productNames = [];
$.each(jsonData, function(index, product) {
productNames.push(product.name + "#" + product.image + "#" + product.id);
});
$('#typeahead').typeahead({
source: productNames,
highlighter: function(item) {
var parts = item.split('#'),
html = '<div><div class="typeahead-inner" id="' + parts[2] + '">';
html += '<div class="item-img" style="background-image: url(' + parts[1] + ')"></div>';
html += '<div class="item-body">';
html += '<p class="item-heading">' + parts[0] + '</p>';
html += '</div>';
html += '</div></div>';
var query = this.query;
var reEscQuery = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var reQuery = new RegExp('(' + reEscQuery + ')', "gi");
var jElem = $(html);
var textNodes = $(jElem.find('*')).add(jElem).contents().filter(function() {
return this.nodeType === 3;
});
textNodes.replaceWith(function() {
return $(this).text().replace(reQuery, '<strong>$1</strong>');
});
return jElem.html();
},
updater: function(selectedName) {
var name = selectedName.split('#')[0];
return name;
}
});
},
initialize: function() {
var _this = this;
_this.typeaheadInit();
}
};

- 41
- 3