admin管理员组

文章数量:1323707

I'm trying to use Typeahead/Bloodhound for suggestions and search. For simplicity's sake, let's assume I have two types of model objects - Country and City.

public class Country
{
    public string Name { get; set; }
}

(Server-side is in ASP.NET, but that's irrelevant for the question).

City is practically the same as Country, except with a different name.

Anyway, before styling, I expect the end result to look like this:

(If it's not obvious, I've written "AL" in the textbox, the remaining letters form the first suggestion)

And I'm able to achieve this easily by using multiple Bloodhounds:

var countries = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/countries/%QUERY',
        wildcard: '%QUERY'
    }
});

var cities = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/cities/%QUERY',
        wildcard: '%QUERY'
    }
});

and multiple input objects to typeahead:

$('#remote .typeahead').typeahead(null,
    {
        name: 'countries',
        display: 'name',
        source: countries,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any countries that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebarspile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Countries</h2>'
        }

    },
    {
        name: 'cities',
        display: 'name',
        source: cities,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any cities that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebarspile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Cities</h2>'
        }

    });

However, in my real-world scenario, I have about 10 datasets. Creating 10 separate queries, bined with JSON serialization/deserialization sould probably kill my servers on the spot, especially with multiple users.

What I'd prefer is to have a posite DTO:

public class CompositeSearchResult
{
    public List<Country> Countries { get; set; }
    public List<City> Cities { get; set; }
    //... and many others
}

... while somehow handling the plex object on the client with Bloodhound. Is this possible?

I'm trying to use Typeahead/Bloodhound for suggestions and search. For simplicity's sake, let's assume I have two types of model objects - Country and City.

public class Country
{
    public string Name { get; set; }
}

(Server-side is in ASP.NET, but that's irrelevant for the question).

City is practically the same as Country, except with a different name.

Anyway, before styling, I expect the end result to look like this:

(If it's not obvious, I've written "AL" in the textbox, the remaining letters form the first suggestion)

And I'm able to achieve this easily by using multiple Bloodhounds:

var countries = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/countries/%QUERY',
        wildcard: '%QUERY'
    }
});

var cities = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/cities/%QUERY',
        wildcard: '%QUERY'
    }
});

and multiple input objects to typeahead:

$('#remote .typeahead').typeahead(null,
    {
        name: 'countries',
        display: 'name',
        source: countries,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any countries that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebars.pile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Countries</h2>'
        }

    },
    {
        name: 'cities',
        display: 'name',
        source: cities,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any cities that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebars.pile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Cities</h2>'
        }

    });

However, in my real-world scenario, I have about 10 datasets. Creating 10 separate queries, bined with JSON serialization/deserialization sould probably kill my servers on the spot, especially with multiple users.

What I'd prefer is to have a posite DTO:

public class CompositeSearchResult
{
    public List<Country> Countries { get; set; }
    public List<City> Cities { get; set; }
    //... and many others
}

... while somehow handling the plex object on the client with Bloodhound. Is this possible?

Share Improve this question edited Apr 26, 2017 at 14:02 nikovn asked Apr 26, 2017 at 13:23 nikovnnikovn 2,0005 gold badges24 silver badges31 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 10

I did it!

First I found out, that Bloodhound caching is smart - so if a search query has already been conducted by it, it will no longer use the network - and will look in the cache instead.

So this means that if the URL for both datasets is the same, the query is only performed once on the server, and the result set is then cached and used by all bloodhounds.

Going back to the simple Countries+Cities example, it should look like this:

var countries = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/positesearch/%QUERY',
        wildcard: '%QUERY',
        transform: function(d) {
            return d.countries;
        }
    }
});

var cities = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/positesearch/%QUERY',
        wildcard: '%QUERY',
        transform: function(d) {
            return d.cities;
        }
    }
});

The only difference in both cases is the "transform" function in the remote settings.

Then, by using the exact same CompositeSearch object from the question, I'm able to retrieve both datasets (essentially the same as in the screenshot) at one go instead of 2 - confirmed by the Network tab of my browser :)

本文标签: javascriptHow to use multiple datasets in one go with Typeahead and BloodhoundStack Overflow