meteor-typeahead
Twitter's typeahead.js autocomplete package, wrapped for Meteor 1.0+. Issue command meteor add sergeyt:typeahead
to install the package.
Initializing typeahead
When the DOM is loaded through Meteor.startup on each template
Meteor.startup(function() {
Meteor.typeahead.inject();
});
with iron:router
Using iron:router the Meteor.startup is already triggered because it loads the template or the loading template and then inject the data. It must be delayed to when iron:router knows it is rendered completely.
Template.demo.rendered = function() {
Meteor.typeahead.inject();
};
Examples
See demo application in this repository to find more examples.
data-source attribute
<input class="form-control typeahead" name="team" type="text"
placeholder="NBA teams"
autocomplete="off" spellcheck="off"
data-source="nba"/>
Nba = new Meteor.Collection("nba");
if (Meteor.isServer){
Nba.insert({name:'Boston Celtics'});
// fill Nba collection
}
Template.demo.helpers({
nba: function() {
return Nba.find().fetch().map(function(it){ return it.name; });
}
});
Multiple datasets
<template name="demo">
<div class="form-group">
<input class="form-control typeahead" name="team" type="text"
placeholder="NBA and NHL teams"
autocomplete="off" spellcheck="off"
data-sets="teams"/>
</div>
</template>
<template name="team">
<h4><i>{{name}}</i></h4>
</template>
Template.demo.helpers({
teams: function() {
return [
{
name: 'nba-teams',
valueKey: 'name',
local: function() { return Nba.find().fetch(); },
header: '<h3 class="league-name">NBA Teams</h3>',
template: 'team'
},
{
name: 'nhl-teams',
valueKey: 'name',
local: function() { return Nhl.find().fetch(); },
header: '<h3 class="league-name">NHL Teams</h3>',
template: 'team'
}
];
}
});
Custom template to render suggestion
<input class="form-control typeahead" name="repo" type="text"
placeholder="open source projects by Twitter"
autocomplete="off" spellcheck="off"
data-source="repos" data-template="repo"/>
<template name="repo">
<p class="repo-language">{{language}}</p>
<p class="repo-name">{{name}}</p>
<p class="repo-description">{{description}}</p>
</template>
Repos = new Meteor.Collection("repos");
if (Meteor.isServer){
Meteor.startup(function(){
Repos.remove({});
// fill repos from private repos.json asset
JSON.parse(Assets.getText('repos.json')).forEach(function(it){
Repos.insert(it);
});
});
}
if (Meteor.isClient){
Template.demo.helpers({
repos: function() {
// this only works if returned objects have
// an attribute named "value" containing the text
// See docs for "data-value-key" attribute
return Repos.find().fetch();
}
});
}
Server side search
<input class="form-control typeahead" name="search" type="text" placeholder="Type to query"
autocomplete="off" spellcheck="off"
data-source="search"/>
BigCollection = new Meteor.Collection('bigcollection');
if (Meteor.isServer) {
Meteor.startup(function() {
if (!BigCollection.find().count()) {
// fill BigCollection
}
});
Meteor.methods({
search: function(query, options) {
options = options || {};
// guard against client-side DOS: hard limit to 50
if (options.limit) {
options.limit = Math.min(50, Math.abs(options.limit));
} else {
options.limit = 50;
}
// TODO fix regexp to support multiple tokens
var regex = new RegExp("^" + query);
return BigCollection.find({name: {$regex: regex}}, options).fetch();
}
});
} else {
Template.demo.helpers({
search = function(query, sync, callback) {
Meteor.call('search', query, {}, function(err, res) {
if (err) {
console.log(err);
return;
}
callback(res.map(function(v){ return {value: v.name}; }));
});
}
});
}
Catching selected event with id
Template.example.rendered = function() {
Meteor.typeahead.inject();
}
Template.example.helpers({
items: function() {
// data source function
// TODO fetch items from meteor collection
return someCollections.find().fetch().map(function(object){ return {id: object._id, value: object.value}; });
},
selected: function(event, suggestion, datasetName) {
// event - the jQuery event object
// suggestion - the suggestion object
// datasetName - the name of the dataset the suggestion belongs to
// TODO your event handler here
console.log(suggestion.id);
}
});
Template:
<template name="example">
<input placeholder="Kies een plaats" autocomplete="off" spellcheck="off"
data-source="items" data-select="selected"/>
</template>
Styling
By default, there is no style applied with this package. If you want the same styling as in the demo app, please do the following:
- add bootstrap:
meteor add twbs:bootstrap
- add the style.css file to your application