typeahead.jsbootstrap-typeaheadbloodhoundbootstrap-tokenfield

Bootstrap Tokenfield with Typeahead / Bloodhound exclude tokens


I'm using bootstrap-tokenfield with typeahead/bloodhound.

I can prevent the same token from being used twice in the tokenfield, but the same token still appears in the typeahead response. How can I exclude tokens that are already in the tokenfield?

var engine = new Bloodhound({
  remote: {
    url: API_URL + '?action=message_friends&q=%QUERY',
    filter: function (response) {
      return $.map(response.users, function (user) {
        return {
          value: user.user_id,
          label: user.name
        };
      });
    }
  },
  datumTokenizer: function(d) {
    return Bloodhound.tokenizers.whitespace(d.value); 
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace    
);

engine.initialize();

$('#to-tags').tokenfield({
  typeahead: [
    {
      hint: false
    }, 
    {
      name: 'users',
      displayKey: 'label',
      source: engine.ttAdapter()
    }
  ]
}).on('tokenfield:createtoken', function (event) {
  var existingTokens = $(this).tokenfield('getTokens');
  $.each(existingTokens, function(index, token) {
    if (token.value === event.attrs.value) {
      event.preventDefault();
    }
  });
});

Solution

  • Updated the filter function to remove users already in the token field:

    var engine = new Bloodhound({
            remote: {
                url: API_URL + '?action=message_friends&q=%QUERY',
                filter: function (response) {
                    var tagged_user = $('#to-tags').tokenfield('getTokens');
                    return $.map(response.users, function (user) {
                        var exists = false;
                        for (i=0; i < tagged_user.length; i++) {
                            if (user.user_id == tagged_user[i].value) {
                                var exists = true;
                            }
                        }
                        if (!exists) {
                            return {
                                value: user.user_id,
                                label: user.name
                            };
                        }
                    });
                }
            },
            datumTokenizer: function (d) {
                return Bloodhound.tokenizers.whitespace(d.value);
            },
            queryTokenizer: Bloodhound.tokenizers.whitespace
        });
    
        engine.initialize();
    
        $('#to-tags').tokenfield({
            delimiter: false,
            typeahead: [
                {
                    hint: false
                }, 
                {
                    name: 'users',
                    displayKey: 'label',
                    source: engine.ttAdapter()
                }
            ]
        })
        .on('tokenfield:createtoken', function (e) {
            var existingTokens = $(this).tokenfield('getTokens');
            if (existingTokens.length) {
                $.each(existingTokens, function(index, token) {
                    if (token.value === e.attrs.value) {
                        e.preventDefault();
                    }
                });
            }
        });