最新服务器上的版本,以后用这个
edit | blame | history | raw

Migrating to typeahead.js v0.10.0

Preamble

v0.10.0 of typeahead.js ended up being almost a complete rewrite. Many things
stayed the same, but there were a handful of changes you need to be aware of
if you plan on upgrading from an older version. This document aims to call out
those changes and explain what you need to do in order to have an painless
upgrade.

Notable Changes

First Argument to the jQuery Plugin

In v0.10.0, the first argument to jQuery#typeahead is an options hash that
can be used to configure the behavior of the typeahead. This is in contrast
to previous versions where jQuery#typeahead expected just a series of datasets
to be passed to it:

// pre-v0.10.0
$('.typeahead').typeahead(myDataset);

// v0.10.0
$('.typeahead').typeahead({
  highlight: true,
  hint: false
}, myDataset);

If you're fine with the default configuration, you can just pass null as the
first argument:

$('.typeahead').typeahead(null, myDataset);

Bloodhound Suggestion Engine

The most notable change in v0.10.0 is that typeahead.js has been decomposed into
a suggestion engine and a UI view. As part of this change, the way you configure
datasets has changed. Previously, a dataset config would have looked like:

{
  valueKey: 'num',
  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
  prefetch: '/prefetch',
  remote: '/remote?q=%QUERY'
}

In v0.10.0, an equivalent dataset config would look like:

{
 displayKey: 'num',
 source: mySource
}

As you can see, local, prefetch, and remote are no longer defined at the
dataset level. Instead, all you set in a dataset config is source. source is
expected to be a function with the signature function(query, callback). When a
typeahead's query changes, suggestions will be requested from source. It's
expected source will compute the suggestion set and invoke callback with an array
of suggestion objects. The typeahead will then go on to render those suggestions.

If you're wondering if you can still configure local, prefetch, and
remote, don't worry, that's where the Bloodhound suggestion engine comes in.
Here's how you would define mySource which was referenced in the previous
code snippet:

var mySource = new Bloodhound({
  datumTokenizer: function(d) { 
    return Bloodhound.tokenizers.whitespace(d.num); 
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
  prefetch: '/prefetch',
  remote: '/remote?q=%QUERY'
});

// this kicks off the loading and processing of local and prefetch data
// the suggestion engine will be useless until it is initialized
mySource.initialize();

In the above snippet, a Bloodhound suggestion engine is initialized and that's
what will be used as the source of your dataset. There's still one last thing
that needs to be done before you can use a Bloodhound suggestion engine as the
source of a dataset. Because datasets expect source to be function, the
Bloodhound instance needs to be wrapped in an adapter so it can meet that
expectation.

mySource = mySource.ttAdapter();

Put it all together:

var mySource = new Bloodhound({
  datumTokenizer: function(d) { 
    return Bloodhound.tokenizers.whitespace(d.num); 
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  local: [{ num: 'one' }, { num: 'two' }, { num: 'three' }],
  prefetch: '/prefetch',
  remote: '/remote?q=%QUERY'
});

mySource.initialize();

$('.typeahead').typeahead(null, {
  displayKey: 'num',
  source: mySource.ttAdapter()
});

Tokenization Methods Must Be Provided

The Bloodhound suggestion engine is token-based, so how datums and queries are
tokenized plays a vital role in the quality of search results. Pre-v0.10.0,
it was not possible to configure the tokenization method. Starting in v0.10.0,
you must specify how you want datums and queries tokenized.

The most common tokenization methods split a given string on whitespace or
non-word characters. Bloodhound provides implementations for those methods
out of the box:

// returns ['one', 'two', 'twenty-five']
Bloodhound.tokenizers.whitespace('  one two  twenty-five');

// returns ['one', 'two', 'twenty', 'five']
Bloodhound.tokenizers.nonword('  one two  twenty-five');

For query tokenization, you'll probably want to use one of the above methods.
For datum tokenization, this is where you may want to do something a tad bit
more advanced.

For datums, sometimes you want tokens to be dervied from more than one property.
For example, if you were building a search engine for GitHub repositories, it'd
probably be wise to have tokens derived from the repo's name, owner, and
primary language:

var repos = [
  { name: 'example', owner: 'John Doe', language: 'JavaScript' },
  { name: 'another example', owner: 'Joe Doe', language: 'Scala' }
];

function customTokenizer(datum) {
  var nameTokens = Bloodhound.tokenizers.whitespace(datum.name);
  var ownerTokens = Bloodhound.tokenizers.whitespace(datum.owner);
  var languageTokens = Bloodhound.tokenizers.whitespace(datum.language);

  return nameTokens.concat(ownerTokens).concat(languageTokens);
}

There may also be the scenario where you want datum tokenization to be performed
on the backend. The best way to do that is to just add a property to your datums
that contains those tokens. You can then provide a tokenizer that just returns
the already existing tokens:

var sports = [
  { value: 'football', tokens: ['football', 'pigskin'] },
  { value: 'basketball', tokens: ['basketball', 'bball'] }
];

function customTokenizer(datum) { return datum.tokens; }

There are plenty of other ways you could go about tokenizing datums, it really
just depends on what you are trying to accomplish.

String Datums Are No Longer Supported

Dropping support for string datums was a difficult choice, but in the end it
made sense for a number of reasons. If you still want to hydrate the suggestion
engine with string datums, you'll need to use the filter function:

var engine = new Bloodhound({
  prefetch: {
    url: '/data',
    filter: function(data) {
      // assume data is an array of strings e.g. ['one', 'two', 'three']
      return $.map(data, function(str) { return { value: str }; });
    },
    datumTokenizer: function(d) { 
      return Bloodhound.tokenizers.whitespace(d.value); 
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace
  }
});

Precompiled Templates Are Now Required

In previous versions of typeahead.js, you could specify a string template along
with the templating engine that should be used to compile/render it. In
v0.10.0, you can no longer specify templating engines; instead you must provide
precompiled templates. Precompiled templates are functions that take one
argument: the context the template should be rendered with.

Most of the popular templating engines allow for the creation of precompiled
templates. For example, you can generate one using Handlebars by doing the
following:

var precompiledTemplate = Handlebars.compile('<p>{{value}}</p>');

CSS Class Changes

tt-is-under-cursor is now tt-cursor - Applied to a hovered-on suggestion (either via cursor or arrow key).

tt-query is now tt-input - Applied to the typeahead input field.

Something Missing?

If something is missing from this migration guide, pull requests are accepted :)