Twitter Typeahead.js - remove datum upon selection
Asked Answered
B

3

9

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.

Beckibeckie answered 10/1, 2014 at 12:53 Comment(2)
Why not just filter the data before passing it into the typeahead?Headforemost
Because there's no mechanism to "refilter" it without calling .typeahead('destroy') and re-initializing typeahead with another prefetch call. I don't want to have to POST after ever typeahead:selected event.Beckibeckie
C
0

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:

  1. 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.
  2. Cache control: The ability to deny typeahead control to use the cache for the last executed suggestion search.
  3. 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.com/Svakinn/typeahead.js/tree/typeaheadSimple There are also live live JQuery and Knockout examples available:
https://github.com/Svakinn/typeahead.js/blob/typeaheadSimple/Examples.md

Chalybite answered 14/1, 2014 at 0:40 Comment(1)
This looks great - I'm testing out your solution now.Koreykorff
E
14

You 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.net/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 comment 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);
Esmaria answered 1/7, 2014 at 13:1 Comment(6)
This worked fantastically. I've looked quite a bit for a solution to this (I didn't want to have to clear the cache totally on each typeahead event when I know there are no more results in my remote source). Great answer! :)Alburga
One important addition: You should also set the limit option for Bloodhound to something very large, or even Infinity because the limit on suggestions is applied before your custom filter is called. Worst case scenario: Of 100 possible results, you would filter out 5 with your custom filter, but Bloodhound only gives you those 5 due to suggestion limit leading to an empty result.Natalianatalie
Excellent catch! I have not yet used Bloodhound with a large enough data set that a limit was necessary.Esmaria
Definitely a better solution than the accepted solution.Moneymaker
Just a small update to this, instead of using jQuery's val, they recommend using $('.typeahead').typeahead('val', myVal); because it looks like it breaks a little in the current version. github.com/twitter/typeahead.js/blob/master/doc/…Diaphoretic
Thanks for this suggestion, it worked! But be aware, that in the current version of Bloodhound (0.11.1), you have to use data.search instead of data.get to get the list of matching items. Also, be aware that suggestion.val in the filter function above is accessing the val property of the values of the Bloodhound data source. If you have any other property to hold your data, you'll need to adapt this (this might be a beginners mistake, but I needed a few minutes to search for it nontheless)Supination
C
0

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:

  1. 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.
  2. Cache control: The ability to deny typeahead control to use the cache for the last executed suggestion search.
  3. 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.com/Svakinn/typeahead.js/tree/typeaheadSimple There are also live live JQuery and Knockout examples available:
https://github.com/Svakinn/typeahead.js/blob/typeaheadSimple/Examples.md

Chalybite answered 14/1, 2014 at 0:40 Comment(1)
This looks great - I'm testing out your solution now.Koreykorff
O
-1

try this on, it's work for me.

$('#selector').typeahead('setQuery', "");
Ogham answered 15/1, 2014 at 8:22 Comment(1)
All that does is empty the query. It has no affect on the array of datums...calling .typeahead('setQuery',"") does not empty selected items.Beckibeckie

© 2022 - 2024 — McMap. All rights reserved.