dabadaba
dabadaba

Reputation: 9522

Bloodhound matching not working with special characters

I am using typeahead.js with Bloodhound to search users using a local source:

let users = [
  {name: 'John Doe ([email protected])', value: '3421'},
  {name: 'Jane Doe ([email protected])', value: '8100'},
];

The matching and display key is name:

$('input').typeahead(
  {
    minLength: 1,
    highlight: true
  },
  {
    name: 'users',
    displayKey: 'name',
    source: new Bloodhound({
      datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
      queryTokenizer: Bloodhound.tokenizers.whitespace,
      local: users
    })
  }
);

It does match when searching by the user's name, e.g. "John" or "Jane". But not if you search by email, e.g. "john.doe", "test" or "email.org".

However, if the parentheses are removed, e.g. 'John Doe [email protected]' then "john.doe" does match. Not "email.org" though.

Other special characters like <, e.g. 'John Doe <[email protected]>' has the same issue.

Why are special characters disrupting the datum matching and what can I do to help it?

Here is an working pen.

I can have an extra attribute:

let users = [
  {name: 'John Doe ([email protected])', value: '3421', match: 'John Doe [email protected]'},
  {name: 'Jane Doe ([email protected])', value: '8100', match: 'Jane Doe [email protected]'},
];

And match by the new key:

datumTokenizer: Bloodhound.tokenizers.obj.whitespace('match')

Or I can have a new property email and have the following datum tokenizer:

datumTokenizer: u => Bloodhound.tokenizers.whitespace([u.name + ' ' + u.email])

But that's far from ideal. But how can I just make the name key match?

Upvotes: 1

Views: 575

Answers (2)

user1660678
user1660678

Reputation: 35

use the nonword tokenizer for both your datumTokenizer and queryTokenizer.

Upvotes: 0

Kyr
Kyr

Reputation: 1025

It seems that you need to use own tokenizer, like this.

const customTokenizer = (user) => {
  const tokens = user.name.split(/[\s()]+/);
  console.info('Tokenizer', user, '=>', tokens);
  return tokens;
};

let users = [{
    name: 'John Doe ([email protected])',
    value: '3421'
    // , email: '[email protected]'
  },
  {
    name: 'Jane Doe ([email protected])',
    value: '8100'
    //, email: '[email protected]'
  },
];

$('input').typeahead({
  minLength: 1,
  highlight: true
}, {
  name: 'users',
  displayKey: 'name',
  source: new Bloodhound({
    // datumTokenizer: u => Bloodhound.tokenizers.whitespace([u.name + ' ' + u.email]),
    datumTokenizer: customTokenizer,
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    local: users
  })
});
.tt-menu {
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script>

<div id="search">
  <input type="text" placeholder="Search user">
</div>

Upvotes: 1

Related Questions