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:

```javascript
// 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:

```javascript
$('.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:

```javascript
{
  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:

```javascript
{
 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:

```javascript
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:

```javascript
// 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:

```javascript
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:

```javascript
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:

```javascript
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:

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

[Handlebars]: http://handlebarsjs.com/

### 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 :)
