I have an form with numerous text inputs for which 10 of them I'd like to use typeahead.js with Bloodhound. I have it working for 2 of them - they both include prefetch and remote data sources. But there's a fair amount of jQuery code for each instance of typeahead/Bloodhound and I'm curious if anyone has tried to "genericize" typeahead/Bloodhound to handle multiple different input elements each with a different data source? It might be more trouble than it's worth, but I'm a bit concerned about the amount of code the page will have to load.
My environment is Spring/MVC, Hibernate (Oracle db), Bootstrap.
Here's a sample of one typeahead/Bloodhound instance. It's in a function because I'm adding row's of inputs dynamically so I have to call this function after a new row is added to enable typeahead on the text input in that row.
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 what I'm really asking is if anyone has created a "template" version of typeahead/Bootstrap that can then be instantiated for each individual text input.
The typeahead input fields are very popular in modern web forms. The main purpose of using typeahead is to improve the user experience by supplying hints or a list of possible choices based on the text they've entered while filling a form or searching something — like the Google instant search.
Performs search to retrieve list of places by input text and location vicinity. Address Autocomplete takes free form text as input. It could be a part of an address. Location could be provided either as latitude/longitude or as country ISO code. It returns consolidated list of addresses based on the input text.
by Tom Bertrand. jQuery plugin that provides Typeahead (autocomplete) Search preview from Json object(s) via same domain Ajax request or cross domain Jsonp and offers data compression inside Local Storage. The plugin is built with a lot of options and callbacks to allow customization.
Sorry if this was a question with an obvious answer, but I'm new to the Java, Spring/Hibernate, jQuery, etc., stack. Using Firebug I was able to figure out what both typeahead and Bloodhound required 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 generic and I'm not crazy about all the parameters in the call to the Bloodhound initialization function, but since I'll have about 10 or more typeahead-enabled controls on the page it will be fairly easy to add the rest of them with just a few lines of code. Those typeahead controls that are not part of the dynamically created rows on the page won't need separate functions for initialization, but can be initialized with just 3 lines of code. I'm definitely open to any comments or suggestions for improvement, including any thoughts that this is a stupid idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With