sergeyt:typeahead

v3.1.0Published 3 months ago

meteor-typeahead Build Status LICENSE meteor package version

Deps Status DevDeps Status

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

1Meteor.startup(function() {
2  Meteor.typeahead.inject();
3});

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.

1Template.demo.rendered = function() {
2  Meteor.typeahead.inject();
3};

Examples

See demo application in this repository to find more examples.

data-source attribute

1<input class="form-control typeahead" name="team" type="text"
2       placeholder="NBA teams"
3       autocomplete="off" spellcheck="off"
4       data-source="nba"/>
1Nba = new Meteor.Collection("nba");
2
3if (Meteor.isServer){
4	Nba.insert({name:'Boston Celtics'});
5	// fill Nba collection
6}
7
8Template.demo.helpers({
9  nba: function() {
10    return Nba.find().fetch().map(function(it){ return it.name; });
11  }
12});

Multiple datasets

1<template name="demo">
2  <div class="form-group">
3    <input class="form-control typeahead" name="team" type="text"
4           placeholder="NBA and NHL teams"
5           autocomplete="off" spellcheck="off"
6           data-sets="teams"/>
7  </div>
8</template>
9
10<template name="team">
11	<h4><i>{{name}}</i></h4>
12</template>
1Template.demo.helpers({
2  teams: function() {
3    return [
4      {
5        name: 'nba-teams',
6        valueKey: 'name',
7        local: function() { return Nba.find().fetch(); },
8        header: '<h3 class="league-name">NBA Teams</h3>',
9        template: 'team'
10      },
11      {
12        name: 'nhl-teams',
13        valueKey: 'name',
14        local: function() { return Nhl.find().fetch(); },
15        header: '<h3 class="league-name">NHL Teams</h3>',
16        template: 'team'
17      }
18    ];
19  }
20});

Custom template to render suggestion

1<input class="form-control typeahead" name="repo" type="text"
2       placeholder="open source projects by Twitter"
3       autocomplete="off" spellcheck="off"
4       data-source="repos" data-template="repo"/>
5
6<template name="repo">
7       <p class="repo-language">{{language}}</p>
8       <p class="repo-name">{{name}}</p>
9       <p class="repo-description">{{description}}</p>
10</template>
1Repos = new Meteor.Collection("repos");
2
3if (Meteor.isServer){
4	Meteor.startup(function(){
5		Repos.remove({});
6		// fill repos from private repos.json asset
7		JSON.parse(Assets.getText('repos.json')).forEach(function(it){
8			Repos.insert(it);
9		});
10	});
11}
12
13if (Meteor.isClient){
14  Template.demo.helpers({
15    repos: function() {
16      // this only works if returned objects have
17      // an attribute named "value" containing the text
18      // See docs for "data-value-key" attribute
19      return Repos.find().fetch();
20    }
21  });
22}
1<input class="form-control typeahead" name="search" type="text" placeholder="Type to query"
2       autocomplete="off" spellcheck="off"
3       data-source="search"/>
1BigCollection = new Meteor.Collection('bigcollection');
2
3if (Meteor.isServer) {
4	Meteor.startup(function() {
5		if (!BigCollection.find().count()) {
6			// fill BigCollection
7		}
8	});
9
10	Meteor.methods({
11		search: function(query, options) {
12			options = options || {};
13
14			// guard against client-side DOS: hard limit to 50
15			if (options.limit) {
16				options.limit = Math.min(50, Math.abs(options.limit));
17			} else {
18				options.limit = 50;
19			}
20
21			// TODO fix regexp to support multiple tokens
22			var regex = new RegExp("^" + query);
23			return BigCollection.find({name: {$regex:  regex}}, options).fetch();
24		}
25	});
26} else {
27
28  Template.demo.helpers({
29    search = function(query, sync, callback) {
30      Meteor.call('search', query, {}, function(err, res) {
31        if (err) {
32          console.log(err);
33          return;
34        }
35        callback(res.map(function(v){ return {value: v.name}; }));
36      });
37    }
38  });
39}

Catching selected event with id

1Template.example.rendered = function() {
2  Meteor.typeahead.inject();
3}
4
5Template.example.helpers({
6  items: function() {
7    // data source function
8    // TODO fetch items from meteor collection
9    return someCollections.find().fetch().map(function(object){ return {id: object._id, value: object.value}; });
10  },
11  selected: function(event, suggestion, datasetName) {
12    // event - the jQuery event object
13    // suggestion - the suggestion object
14    // datasetName - the name of the dataset the suggestion belongs to
15    // TODO your event handler here
16    console.log(suggestion.id);
17  }
18});

Template:

1<template name="example">
2  <input placeholder="Kies een plaats" autocomplete="off" spellcheck="off"
3      data-source="items" data-select="selected"/>
4</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