Twitter's typeahead-bloodhound: What is the equivalent of "%QUERY" when using ajax.data and POST?
Asked Answered
H

3

3

If one uses Bloodhound with GET:

// Typeahead
personsBloodhound = new Bloodhound({
    datumTokenizer: function (person) { return person.name; },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    remote: {
        url: '/ajax/Persons/List?nameContains=%QUERY',
        ajax: {
            beforeSend: function(xhr) {
                $(".searching-person").show();
            },
            data: {
                "pageSize": 4,
                "otherParam1": "blah",
                "otherParam2": "bleh",
            }
        },
        filter: function (response) {
            $(".searching-person").hide();
            return response.persons;
        }
    }
});

One simply uses %QUERY in the URL.

Now....
If one uses Bloodhound with POST, what should I use instead of %QUERY?

// Typeahead
personsBloodhound = new Bloodhound({
    datumTokenizer: function (person) { return person.name; },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    remote: {
        url: '/ajax/Persons/List',
        ajax: {
            type: "POST",
            beforeSend: function(xhr) {
                $(".searching-person").show();
            },
            data: {
                "nameContains": ....WHAT GOES HERE?????......
                "pageSize": 4,
                "otherParam1": "blah",
                "otherParam2": "bleh",
            }
        },
        filter: function (response) {
            $(".searching-person").hide();
            return response.persons;
        }
    }
});

If it was not clear, the question is:
What is the equivalent of %QUERY when using POST within Bloodhound's remote?

The documentation isn't clear about this, (proof): https://github.com/twitter/typeahead.js/blob/master/doc/bloodhound.md#remote

Also tried using:

 "nameContains": $("#my-input-that-uses-typeahead").val(),

But didn't work.

Harbot answered 8/6, 2014 at 16:57 Comment(0)
T
0

You have to alter the URL somehow, otherwise the bloodhound wont send an other request (see https://mcmap.net/q/698636/-typeahead-bloodhound-post-request) and livesearch/typeahead wont work.

So ("#my-input-that-uses-typeahead").val() works just fine in combination with a dynamic URL (e.g.http://127.0.0.1:1234/REST_API/_search?useless=%QUERY) and a beforeSend-function in the ajax setttings.

I gonna file an issue about this behaviour. Using the bloodhound for POST-requests ist VERY awkward and takes away the simplicity intended with typeahead.js.

EDIT:

Also make sure you set the new value for the data in beforeSend and set settings.hasContent = true. Otherwise the initial data will be used.

Example on how it's done: https://github.com/twitter/typeahead.js/issues/542#issuecomment-29995960.

Tiflis answered 27/8, 2014 at 12:9 Comment(2)
kind of ugly, but ok... accepted, also in the link the author of typeahead supports your answerHarbot
He also answered me on Github: github.com/twitter/typeahead.js/issues/…. It seems he wants to change this behaviour with the next release.Camp
L
1

Equivalent of %QUERY when using POST within Bloodhound's remote is query.

Here is a simple example (with detailed explanation) where you can use it for both GET and POST. As you can see I have declared a variable isExtendUrl. If this is set to true then the query (what you type) will be added to the end of the url (you have to give the myurl somehow).

The next variable is isRequestMethod. If this is set to POST, you can use bloodhound for POST calls else you can use it for GET calls. As you can see prepare function has two parameters query and setting. query is the one what you type. If you just want the POST call without GET move prepare key value pair inside remote object.

So, if you have to use JSON body as {gender: 'MALE', name: 'what is typed'} for your POST call. You can have an initial query object with all your key value pairs eg: initialQuery = {gender: 'MALE'}, and the key searchKey which should be added to initialQuery when searching, could be added on prepare like initialQuery[searchKey] = query.

Finally, if the response object of your POST call is an object and you have to extract a specific key value use filter. Eg: Say your response object is

{
  status: 'some status', 
  content: [{array}, {of}, {objects}, ...], 
  someKey: someValue
} 

and you have to get content, then return data.content. Here is a full example

let isExtendUrl = true; //to add query at the end of the url, usually used with GET
let isRequestMethod = 'POST';
let initialQuery = {gender: 'MALE'};
let searchKey = 'name';

let bloodhound = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.whitespace,
    queryTokenizer: Bloodhound.tokenizers.whitespace,

    remote: {
        url: isExtendUrl ? myurl + '%QUERY' : myurl,
        wildcard: '%QUERY',
        filter: function (data) {
            return $.map(data.content, function (obj) {
                return obj;
            });
        }
    }
});

if (isRequestMethod == 'POST') {
    let prepare = function (query, settings) {
        initialQuery[searchKey] = query;
        settings.type = "POST";
        settings.contentType = "application/json; charset=UTF-8";
        settings.data = JSON.stringify(initialQuery);

        return settings;
    }
    bloodhound.remote.prepare = prepare;
}
Lowenstern answered 25/10, 2017 at 8:48 Comment(0)
D
0

Right, after further looking at bloodhound the wildcard is just what to replace not the value.

It doesn't store the query string anywhere. On queryChanged fires and filters remote response. Looks like you'll have to get the query yourself.

"nameContains": $('input#search').val()
Diep answered 26/6, 2014 at 12:20 Comment(2)
so how do I pass the wildcard in a remote that uses a POST ajax?Harbot
Good point, the wildcard was just what to replace in the GET url, not the query to send.Diep
T
0

You have to alter the URL somehow, otherwise the bloodhound wont send an other request (see https://mcmap.net/q/698636/-typeahead-bloodhound-post-request) and livesearch/typeahead wont work.

So ("#my-input-that-uses-typeahead").val() works just fine in combination with a dynamic URL (e.g.http://127.0.0.1:1234/REST_API/_search?useless=%QUERY) and a beforeSend-function in the ajax setttings.

I gonna file an issue about this behaviour. Using the bloodhound for POST-requests ist VERY awkward and takes away the simplicity intended with typeahead.js.

EDIT:

Also make sure you set the new value for the data in beforeSend and set settings.hasContent = true. Otherwise the initial data will be used.

Example on how it's done: https://github.com/twitter/typeahead.js/issues/542#issuecomment-29995960.

Tiflis answered 27/8, 2014 at 12:9 Comment(2)
kind of ugly, but ok... accepted, also in the link the author of typeahead supports your answerHarbot
He also answered me on Github: github.com/twitter/typeahead.js/issues/…. It seems he wants to change this behaviour with the next release.Camp

© 2022 - 2024 — McMap. All rights reserved.