I'm using typeahead.js 0.9.3 and it's working swimmingly. My question is whether it's possible to remove a datum from a dataset upon the "typeahead:selected" event (or any event, for that matter).
I'm fetching the data in the dataset using Typeahead's prefetch
option on page load. I know that I could call $('selector').typeahead('destroy')
and re-initalize typehead and use a filter
in the prefetch
object, but it seems rather heavyweight to have to call the data all over again (we're not caching the data in local storage).
I suppose I'm looking for something akin to the filter
function to iterate through the array of datums and remove the previously-selected (or all selected) datum. It doesn't look like there's a public function in typeahead to do this, but maybe I missed it.
I've read through typeahead's docs and searched here but haven't found an answer.
EDIT: I solved the immediate problem by switching from prefetch
to local
and using an AJAX post
call to get the data, set it as a global variable and then passed it to typeahead
, where I can add/remove items from the global array of data and then destroy/reinitalize typeahead as needed. Far from ideal, but it works.
I'm using typeahead.js 0.9.3 and it's working swimmingly. My question is whether it's possible to remove a datum from a dataset upon the "typeahead:selected" event (or any event, for that matter).
I'm fetching the data in the dataset using Typeahead's prefetch
option on page load. I know that I could call $('selector').typeahead('destroy')
and re-initalize typehead and use a filter
in the prefetch
object, but it seems rather heavyweight to have to call the data all over again (we're not caching the data in local storage).
I suppose I'm looking for something akin to the filter
function to iterate through the array of datums and remove the previously-selected (or all selected) datum. It doesn't look like there's a public function in typeahead to do this, but maybe I missed it.
I've read through typeahead's docs and searched here but haven't found an answer.
EDIT: I solved the immediate problem by switching from prefetch
to local
and using an AJAX post
call to get the data, set it as a global variable and then passed it to typeahead
, where I can add/remove items from the global array of data and then destroy/reinitalize typeahead as needed. Far from ideal, but it works.
- Why not just filter the data before passing it into the typeahead? – Cory Danielson Commented Jan 10, 2014 at 18:43
-
Because there's no mechanism to "refilter" it without calling
.typeahead('destroy')
and re-initializingtypeahead
with anotherprefetch
call. I don't want to have toPOST
after evertypeahead:selected
event. – rpmartz Commented Jan 10, 2014 at 20:06
3 Answers
Reset to default 14You can achieve this functionality in Typeahead 0.10 on any Bloodhound dataset, whether remote, prefetched or local.
Just track which data has been selected independently of the Bloodhound dataset and do not use Bloodhound#ttAdapater()
as your typeahead source. The ttAdapter method is simply a wrapper for Bloodhound#get(query, cb)
— so instead of it, call get(query, cb)
directly with a custom callback that checks each suggestion against the current selections.
Here’s a JSFiddle — http://jsfiddle/likeuntomurphy/tvp9Q/
var selected = [];
var select = function(e, datum, dataset) {
selected.push(datum.val);
$("#selected").text(JSON.stringify(selected));
$("input.typeahead").typeahead("val", "");
}
var filter = function(suggestions) {
return $.grep(suggestions, function(suggestion) {
return $.inArray(suggestion.val, selected) === -1;
});
}
var data = new Bloodhound({
name: 'animals',
local: [{ val: 'dog' }, { val: 'pig' }, { val: 'moose' }],
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d.val);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
// custom suggestion filter is applied after Bloodhound
// limits the set of possible suggestions
// see ment by Basti below
limit: Infinity
});
data.initialize();
$('input.typeahead').typeahead(null,
{
name: 'animals',
displayKey: 'val',
/* don't use
source: data.ttAdapter(), */
source: function(query, cb) {
data.get(query, function(suggestions) {
cb(filter(suggestions));
});
},
templates: {
empty: '<div class="empty-message">No matches.</div>'
}
}
).bind('typeahead:selected', select);
As you pointed out this is tricky if not impossible to do without massive hacking of the current typeahead version. There are 3 things you need:
- Remote as a function option (where you implement your own getter function that accesses your data, filters the query and removes the items you have already selected.
- Cache control: The ability to deny typeahead control to use the cache for the last executed suggestion search.
- On-demand suggestion search, refresh the suggestion results only when you need it (when you enter the input box and start typing your query).
The next typeahead version (0.10 currently in development) may support the required features.
But... it so happens that my (Svakinn) typeahead fork supports all three conditions you need.
Your configuration should supply the getter function, where you select datums from your init data and filter it by query string and already selected options.
remote: yourGetterFunction
Then you need to disable the suggestion cache:
skipCache: true
If you do not want to wait for the next typeahead release, I suggest you try it out:
https://github./Svakinn/typeahead.js/tree/typeaheadSimple
There are also live live JQuery and Knockout examples available:
https://github./Svakinn/typeahead.js/blob/typeaheadSimple/Examples.md
try this on, it's work for me.
$('#selector').typeahead('setQuery', "");