Typehead ajax not populate the suggestion

I am trying to get the data in the dropdown in typeahead, I made the API and frontend ajax but when I input the value in textbox I am not able to see the suggestion in the dropdown. I read the threads other available on google but it was not helpful. this is below the sample code I mentioned please help me with How I get the option in typeahead when I input the value in the textbox.

$("input#userid").typeahead({
  hint: true,
  highlight: true,
  minLength: 2
}, {
  name: 'options',
  displayKey: 'value',
  source: function(query, process) {
    return $.post("https://jsonplaceholder.typicode.com/todos/", {
      keyword: query
    }, function(data) {
      var matches = [];
      $.each(data, function(i, str) {
        matches.push({
          value: str.userId
        });
      });
      return process(matches);
    }, 'json');
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/typeahead.js@0.11.1/dist/typeahead.bundle.min.js"></script>
<input class="form-control" type="text" placeholder="UserID" id="userid">

my API responding me like this array :

{res: 'OK', data: {userId: "John"}}
res: 'OK'
data: {userId: "John"}
userId: "John"

Hi,

Why are you posting to the endpoint? I would have thought that you wanted to fetch a resource, as opposed to create one.

2 Likes

how are you eaching on something that isnt an array?

Hi @wawane7256, in addition to what @James_Hibbard said, according to the docs you need to accept another asyncResults callback as the 3rd source parameter for results that are getting fetched asynchronously – the 2nd parameter would be a callback that is supposed to get called immediately.

BTW @m_hutley, the jQuery $.each() utility also lets you iterate over object properties, so this shouldn’t be the issue here.

s’gonna be very confused then when it takes in the string “OK” and tries to .userId it… go look at the object that the API is returning again…just because you called your variable data doesnt mean its narrowed the object down…

Either:

  1. data is pointing at the whole object; in which case, each is going to walk to the res property, and fall down trying to do str.userId.
  2. data is pointing at the data element of the return, in which case each walks to userId, and str.userId falls down because you’re trying to .userId the string "John". This is, again, because the data isnt in an array.

Both paths end in the phrase “the code falls down”, so…figure out which one you’re on, and correct as appropriate.

EDIT: Or 3, that ISNT what is being returned, and you’re giving us bad info to work from.

It’s quite confusing. Where does ‘John’ come from? It’s not in https://jsonplaceholder.typicode.com/todos/

What are you trying to achieve with this test?

A query can be added to the url and fetched

'https://jsonplaceholder.typicode.com/todos/?userId=${query}'

All a bit confusing.

So have been having a bit of play with this. I think the jsonplaceholder/users is an easier example to work with than the todos.

On the official typeahead website they provide this example, which I have used as a basis to work from.

html

<input 
  class="typeahead" 
  type="text" 
  placeholder="UserName" 
  id="userName"
>

Javascript
I have opted to use the user names rather than user id for this test

const getByUserName = function (users = []) {
    // return the handler function with users stored in a closure
    return function (name, callback) {
        // use Array.flatMap to filter and map an array
        const matchedNames = users.flatMap(function(user) {
            const foundUser = user.name.toLowerCase().includes(name.toLowerCase())

            return (foundUser) ? [ user.name ] : []
        })

        callback(matchedNames)
    }
}

// fetching the users data first before setting up typeahead
fetch(`https://jsonplaceholder.typicode.com/users`)
    .then((response) => response.json())
    .then((users) => {
        $("#userName").typeahead({
            hint: true,
            highlight: true,
            minLength: 2
        }, {
            name: 'names',
            limit: 10,
            // pass fetched users into getByUserName
            // and get the returned handler
            source: getByUserName(users)
        })
    })

Codepen (try typing ‘cle’ → Clementine Bauch, Clementina DuBuque)

A couple of links that might be useful

1 Like

can I add the headers like this:
headers: { "TOKEN": $('meta[name="token"]').attr("content"), },

@wawane7256

I am struggling to find any detailed documentation on headers. In the docs it says under templates

  • header– Rendered at the top of the dataset when suggestions are present. Can be either a HTML string or a precompiled template. If it’s a precompiled template, the passed in context will contain query and suggestions.

It would have been nice to see a bit more info and some examples.

I did try the following

fetch(`https://jsonplaceholder.typicode.com/users`)
    .then((response) => response.json())
    .then((users) => {
        $("#userName").typeahead({
            hint: true,
            highlight: true,
            minLength: 2
        }, {
            name: 'names',
            limit: 10,
            source: getByUserName(users),
            // header added here
            templates: {
                headers: ['This is a header']
            }
        })
    })

‘This is a header’ is rendered below the input box and above the suggestion. e.g.

This is a header
Leanne Graham

A bit more experimentation, you can change the headers property from an array to a function.

fetch(`https://jsonplaceholder.typicode.com/users`)
    ...
        }, {
            name: 'names',
            limit: 10,
            source: getByUserName(users),
            // header added here
            templates: {
                headers: function(data) {
                    return `Results for ${data.query} from ${data.dataset}:`
                }
            }
        })
    })

If I type ‘lea’ the above would output under the input box

Results for lea from names:
Leanne Graham

The data object that is passed into the headers function in this instance would look like this

{
  dataset: "names"
  query: "lea"
  suggestions: ['Leanne Graham']
}

I’m muddling through this myself, but I hope that helps.

Edit: I have added the templates/header code to the codepen I gave you previously.

templates: { 
   headers: { "TOKEN": $('meta[name="token"]').attr("content"), }
}

but not worked for me

Yours is different to what I suggested. The headers property needs to be an array or a function — as far as I can tell.

Does this work?

templates: { 
   headers: [$('meta[name="token"]').attr("content")]
}

or

templates: { 
   headers: function() {
       return $('meta[name="token"]').attr("content")
   }
}

sorry but it is not working

Can we see your latest code?

I gave you a working example @wawane7256. Did you view that example?

Forgetting typeahead for a second, what does this output to the console?

console.log($('meta[name="token"]').attr("content"))

yes, I have seen, basically, we are using the middleware where when the request goes to the server it first checks the ‘TOKEN’ and I want to send ‘TOKEN’ when the typehead gets the request from the server.
as now I am using this structure for auth in middleware in my all ajax and select2 request.

headers: { "TOKEN": $('meta[name="token"]').attr("content"), }

Ok @wawane7256, I think I have got the wrong end of the stick. This might be closer to what you want.

fetch(
  url here, 
  {
     method: 'POST',
     headers: {
       'Content-type': 'application/json;charset=UTF-8',
       'TOKEN': $('meta[name="token"]').attr("content")
     }
  }
)
  .then((response) => response.json())
  .then((users) => { 
     ...
  }

Or if it is node 18+, I believe the fetch api is now native.

@wawane7256 You have asked in the jquery section, and I have been answering with native JS.

Someone with more experience in Jquery might be able to better guide you, but I believe it maybe along the lines of

$.ajax({
    url: 'yourURL',
    type: 'post',
    data: {},
    headers: {
      'TOKEN': $('meta[name="token"]').attr("content") 
    },
    dataType: 'json'
})
  .done((data) => {
    $(inputElementHere).typeahead({
      hint: true,
      highlight: true,
      minLength: 2
    }, {
      name: 'someNameHere',
      limit: 10,
      source: process(data)
    })
  })

getting error: Uncaught ReferenceError: process is not defined

In the case of the example I gave you I created a function call getByUserName.

I presume that you will need your own custom function and that you are not necessarily getting by username.

That is why I put in ‘process’ as just a default name — as per your original code.

You will need to use a function there that is applicable to the job you doing. So if it is getting by userId then you can create a similar function call getByUserId, then source will then be source: getByUserId(users)

I don’t know the job you are working on, so I can’t be more specific.

You are going to need to customise what I have given you accordingly.