javascriptautocompletetypeahead.jsbloodhound

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 (john.doe@email.org)', value: '3421'},
  {name: 'Jane Doe (test@email.org)', 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 john.doe@email.org' then "john.doe" does match. Not "email.org" though.

Other special characters like <, e.g. 'John Doe <john.doe@email.org>' 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 (john.doe@email.org)', value: '3421', match: 'John Doe john.doe@email.org'},
  {name: 'Jane Doe (test@email.org)', value: '8100', match: 'Jane Doe test@email.org'},
];

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?


Solution

  • 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 (john.doe@email.org)',
        value: '3421'
        // , email: 'john.doe@email.org'
      },
      {
        name: 'Jane Doe (test@email.org)',
        value: '8100'
        //, email: 'test@email.org'
      },
    ];
    
    $('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>