Search code examples
mongoosetypeahead.jsbloodhound

`display` option in typeahead.js does not work


I have been at this for hours, and I am sure I am making a dumb mistake. But I am at a loss...

Here is what I have checked:

docs:

Stackoverflow:

Examples/ google / etc ...

Here is my setup. I have a mongoDB which I have created an API search path for with mongoose / Node.js. I have verified that the search API works correctly.

HTML (pug)

.answer-container
    form(method="POST" enctype="multipart/form-data")#answer-form.form
            label(for="new-answer") Answer:
            input(required minlength="1" maxlength="80" type="text" name="new-answer" id="new-answer" placeholder="Answer Text" autocomplete="off").new-answer-input
            br
            input(type="submit" name="submit" disabled autocomplete="off" value="Submit")#answer-submit-button
    .answer-messages

I have verified that the pug template is working as expected.

JS (typeahead and bloodhound)

    var answer_suggestions = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace("text"),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote:{
            url: 'http://localhost:3000/api/v1/answers/search?text=%QUERY',
            wildcard: '%QUERY'
        }
      });

      $('#new-answer').typeahead({
        hint: true,
        highlight: true,
        autoselect: true,
        minLength: 2
      },
      {
        name: 'answers',
        source: answer_suggestions,
        display: 'text',
        limit: 10
      });

PROBLEM If I remove the display option, I can SEE the results are coming in from the API and everything is working. If I include it, I get no results.

RESULTS Raw results

[
  {
    "_id": "64401c91bc76fdfca320c118",
    "text": "pneumothorax",
    "__v": 0
  },
  {
    "_id": "64403bb708645fb7abbe2db3",
    "text": "pneumothorax",
    "__v": 0
  },
  {
    "_id": "64403bdf08645fb7abbe2dbf",
    "text": "hemopneumothorax",
    "__v": 0
  }
]

I have tried refactoring the data as a json object, I have tried using a function in display but nothing seems to work.

All I want is the results list to simply show the answer text.


Solution

  • I have updated my question to exclude extraneous info and I will provide my answer below.

    The issue was that when I was seeing or logging my data in the typeahead display function or on the page itself it was showing me the NESTED data. Confused? so was I...

    Here is what I thought my API was returning to bloodhound

    [
      {
        "_id": "64401c91bc76fdfca320c118",
        "text": "pneumothorax",
        "__v": 0
      },
      {
        "_id": "64403bb708645fb7abbe2db3",
        "text": "pneumothorax",
        "__v": 0
      },
      {
        "_id": "64403bdf08645fb7abbe2dbf",
        "text": "hemopneumothorax",
        "__v": 0
      }
    ]
    

    Here is what is was ACTUALLY returning.

    { 
    answers:{
    [
      {
        "_id": "64401c91bc76fdfca320c118",
        "text": "pneumothorax",
        "__v": 0
      },
      {
        "_id": "64403bb708645fb7abbe2db3",
        "text": "pneumothorax",
        "__v": 0
      },
      {
        "_id": "64403bdf08645fb7abbe2dbf",
        "text": "hemopneumothorax",
        "__v": 0
      }
    ]
    }
    

    I found this by logging the data in the bloodhound optional transform function. This extra object was my culprit. Since bloodhound stripped it before it got to typeahead, I never saw it.

    HERE is the working code:

        var answer_suggestions = new Bloodhound({
            datumTokenizer: Bloodhound.tokenizers.whitespace('text'),
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            remote:{
                url: 'http://localhost:3000/api/v1/answers/search?text=%QUERY',
                wildcard: '%QUERY',
                transform: (response) => {
                    return $.map(response.answers, function(object) {
                      return { text: object.text };
                    });
                  }
            }
          });
    
          $('#new-answer').typeahead({
            hint: true,
            highlight: true,
            autoselect: true,
            minLength: 2
          },
          {
            name: 'typeahead-answers',
            source: answer_suggestions,
            display: 'text',
            templates: {
                notFound: '<div>Not Found</div>',
                pending: '<div>Loading...</div>',
                suggestion:  function(data) {
                    return `<div>${data.text}</div>`
                },
            },
            limit: 10
          });
    

    You can see I added a custom transform in bloodhound. I also added a custom template in typeahead but this was not required.

    I hope this helps someone. Not enough docs or examples, IMO.

    Data logging is your friend.