Is it possible to consolidate multiple inputs using typeahead.js with different sources?

I have a form with numerous text inputs, for which 10 of them I would like to use typeahead.js with Bloodhound. It works for me for 2 of them - both of them include prefetching and remote data sources. But is there enough jQuery code for each typeahead / Bloodhound instance, and I'm curious if someone tried to "generalize" typeahead / Bloodhound to handle several different input elements, each with a different data source? This may be more of a problem than it costs, but I'm a little worried about the amount of code that will load on the page.

My Spring / MVC environment, Hibernate (Oracle db), Bootstrap.

Here is an example of one instance of typeahead / Bloodhound. This is in a function because I am adding a line of inputs dynamically, so I need to call this function after adding a new line to enable typeahead in the text input on that line.

function initIngredientsTA() { //set the options var ingredBH = new Bloodhound({ limit: 20, datumTokenizer: function(datum) { return Bloodhound.tokenizers.whitespace(datum.name); }, queryTokenizer: Bloodhound.tokenizers.whitespace, prefetch: { url: '/myapp/resources/ingredients.json', cache: false, filter: function(data) { console.log("data: " + data.ingredients); return $.map(data.ingredients, function (ingredient) { return { id : ingredient.id, name : ingredient.name }; }); } }, remote: { url: '/myapp/recipe/addRecipe/getIngredients?searchStr=%QUERY', cache: false, wildcard: '%QUERY', filter: function(data) { console.log("data: " + data); return $.map(data, function (data) { return { id : data.id, name : data.name }; }); } } }); //initialize the suggestion Engine ingredBH.initialize(); $('.ingredDesc').typeahead( { hint: true, highlight: true, minLength: 1 }, { name: 'ingredients', displayKey: 'name', limit: 20, source: ingredBH.ttAdapter(), }) }; 

EDIT: I think I'm really asking if someone created a โ€œtemplateโ€ version of typeahead / Bootstrap, which can then be created for each individual text input.

+7
jquery twitter-bootstrap-3
source share
2 answers

Sorry if this was a question with an obvious answer, but I'm new to Java, Spring / Hibernate, jQuery, etc., the stack. Using Firebug, I was able to figure out what both types and Bloodhound demanded, and came up with the following:

 //token and filter functions function ingredDatumToken(datum) { return Bloodhound.tokenizers.whitespace(datum.name); } function ingredPrefetchFilter(data) { return $.map(data.ingredients, function (ingredient) { return { id : ingredient.id, name : ingredient.name }; }); }; function ingredRemoteFilter(data) { return $.map(data, function (data) { return { id : data.id, name : data.name }; }); }; //Bloodhound initialization function initBloodhound(limit, cache, datumToken, queryToken,prefetchUrl,prefetchFilter, remoteUrl, wildcard, remoteFilter) { var token = Bloodhound.tokenizers.whitespace; var options = {}; var prefetchOptions = {}; var remoteOptions = {}; prefetchOptions['url'] = prefetchUrl; prefetchOptions['cache'] = cache; prefetchOptions['filter'] = prefetchFilter; remoteOptions['url'] = remoteUrl; remoteOptions['cache'] = cache; remoteOptions['wildcard'] = wildcard; remoteOptions['filter'] = remoteFilter; options['limit'] = limit; options['datumTokenizer'] = datumToken === null ? token : datumToken; options['queryTokenizer'] = queryToken === null ? token : queryToken; if (prefetchUrl != null) options['prefetch'] = prefetchOptions; if (remoteUrl != null) options['remote'] = remoteOptions; return new Bloodhound(options); }; //create two Bloodhound engines var ingredBH = initBloodhound(50,false,ingredDatumToken,null,'/myapp/resources/ingredients.json',ingredPrefetchFilter,'/myapp/recipeaddRecipe/getIngredients?searchStr=%QUERY','%QUERY',ingredRemoteFilter); var measureBH = initBloodhound(20,false,null,null,'/myapp/resources/measures.json',null,null,null,null); //add more Bloodhound engines here //typeahead options function initTypeaheadOptions(hint, highlight, minLength) { var options = {}; options['hint'] = hint; options['highlight'] = highlight; options['minLength'] = minLength; return options; } //typeahead dataset function initTypeaheadDataset(name, displayKey, limit, source) { var datasets = {}; datasets['name'] = name; datasets['displayKey'] = displayKey; datasets['limit'] = limit; datasets['source'] = source; return datasets; } //initialize a typeahead control function initIngredientsTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('ingredients', 'name', 20, ingredBH); $('.ingredDesc').typeahead(options,dataset); }; //initialize a typeahead control function initMeasuresTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('measures', null, 20, measureBH); $('.ingredQtyType').typeahead(options,datasets); }; //add more typeahead initialization functions here //call the initialize functions initIngredientsTA(); initMeasuresTA(); //call more initialize functions here 

I'm still working on making it more universal, and I'm not crazy about all the parameters in calling the Bloodhound initialization function, but since there will be about 10 or more controls on the page, it will be quite easy to add the rest of them with just a few lines of code . These elementary controls, which are not part of the dynamically generated lines on the page, do not require separate functions for initialization, but can be initialized with just three lines of code. I am definitely open to any comments or suggestions for improvement, including any thoughts that this is a dumb idea.

+2
source share

I just noticed that there was generosity in this question, so I decided to share some optimizations that I made with my original answer.

The basic functions are in the included file:

typeahead.js

 function setBHPrefetchOpts(cache, prefetchUrl, prefetchFilter) { var prefetchOptions = {}; prefetchOptions['url'] = prefetchUrl; prefetchOptions['cache'] = cache; prefetchOptions['filter'] = prefetchFilter; return prefetchOptions; } function setBHRemoteOpts(cache, wildcard, remoteUrl, remoteFilter) { var remoteOptions = {}; remoteOptions['url'] = remoteUrl; remoteOptions['cache'] = cache; remoteOptions['wildcard'] = wildcard; remoteOptions['filter'] = remoteFilter; return remoteOptions; } function setBHOptions(sufficient, datumToken, queryToken, prefetchOptions, remoteOptions) { var token = Bloodhound.tokenizers.whitespace; var options = {}; options['sufficient'] = sufficient; options['datumTokenizer'] = datumToken === null ? token : datumToken; options['queryTokenizer'] = queryToken === null ? token : queryToken; if (prefetchOptions != null) options['prefetch'] = prefetchOptions; if (remoteOptions != null) options['remote'] = remoteOptions; return options; } function initTypeaheadOptions(hint, highlight, minLength) { var options = {}; options['hint'] = hint; options['highlight'] = highlight; options['minLength'] = minLength; return options; }; function initTypeaheadDataset(name, displayKey, limit, source) { var dataset = {}; dataset['name'] = name; dataset['displayKey'] = displayKey; dataset['limit'] = limit; dataset['source'] = source; return dataset; }; 

To initialize a prefetch (json) type:

 var prefetchOpts = setBHPrefetchOpts(false, '/recipe/resources/measures.json', null); var bhOpts = setBHOptions(50, null, null, prefetchOpts, null); var measureBH = new Bloodhound(bhOpts); function initMeasuresTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('measures', null, 50, measureBH); $('.ingredQtyType').typeahead(options,dataset); }; 

To initialize a remote type:

 var remoteOpts = setBHRemoteOpts(false, '%QUERY', '/recipe/recipe/getQualifiers?searchStr=%QUERY', null); var bhOpts = setBHOptions(50, null, null, null, remoteOpts); var qualifierBH = new Bloodhound(bhOpts); function initQualifiersTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('qualifiers', null, 50, qualifierBH); $('.ingredQual').typeahead(options,dataset); }; 

In both of the above, json consists of separate elements, for example,

["Cup", "Cup", "Ounce", "ounce," pound "," pound sterling "," Tea "," teaspoons "," Dining "," Spoons "]

To initialize both prefetch and remote with more complex json as follows:

{"ingredients": [{"ID": "142", "name": "flour"}, {"identifier": "144", "name": "sugar"}]}

 function ingredDatumToken(datum) { return Bloodhound.tokenizers.whitespace(datum.name); }; function ingredPrefetchFilter(data) { return $.map(data.ingredients, function (ingredient) { return { id : ingredient.id, name : ingredient.name }; }); }; function ingredRemoteFilter(data) { return $.map(data, function (data) { return { id : data.id, name : data.name }; }); }; var prefetchOpts = setBHPrefetchOpts(false, '/recipe/resources/ingredients.json', ingredPrefetchFilter); var remoteOpts = setBHRemoteOpts(false, '%QUERY', '/recipe/recipe/getIngredients?searchStr=%QUERY', ingredRemoteFilter); var bhOpts = setBHOptions(50, ingredDatumToken, null, prefetchOpts, remoteOpts); var ingredBH = new Bloodhound(bhOpts); function initIngredientsTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('ingredients', 'name', 50, ingredBH); $('.ingredDesc').typeahead(options,dataset); }; 

Dynamic query example:

 function setSourceUrl(url, query) { var source = $('#inputSource').val(); var newurl = url + '?searchStr=' + query + '&type=' + source; return newurl; }; var remoteOpts = setBHRemoteOpts(false, '%QUERY', '/recipe/recipe/getSources', null); var remoteOpts['replace'] = function(url, query) {return setSourceUrl(url, query);}; var bhOpts = setBHOptions(50, null, null, null, remoteOpts); var sourceBH = new Bloodhound(bhOpts); function initSourceTA() { var options = initTypeaheadOptions(true,true,1); var dataset = initTypeaheadDataset('source', null, 20, sourceBH); $('.srcTA').typeahead(options,dataset); }; 

Filters can probably be added as generic functions in typeahead.js, but I only have one dataset that required them, so I did not. The same goes for the "replace" option. As said earlier, I'm still relatively new to javascript / jQuery, so I'm sure this solution could be improved, but it made it a lot easier for me than simplifying the setup.

0
source share

All Articles