Search code examples
javascriptjquerybootstrap-4typeahead.js

Twitter typeahead - adding suggestion to dynamically created input boxes


I'm using Twitter typeahead create a suggestion engine for some input boxes on a form. Everything works fine for inputs that are generated when the page is loaded. But if I want to dynamically add new inputs with the same behaviour when a button is pressed, I get the following error: TypeError $(...).typeahead is not a function. The problem seems to be related to trying to initialize the typeahead plugin from within a callback. I use JQuery 3.5.1 and twitter typeahead 0.11.1. How can I get the typeahead method for my dynamic fields?

function typeaheadInitialize(){
    engine = new Bloodhound({
        remote: {
          url: '/api/query_expert_by_email/*',
          wildcard: '*',
          transform: function (response) {
            return response.email;
          }
        },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        datumTokenizer: Bloodhound.tokenizers.whitespace,
      });
    var typeaheadTarget = $('.typeahead');
    typeaheadTarget.typeahead(null, {
      name: 'my-dataset',
      source: engine
    }); //error occurs here: TypeError typeaheadTarget.typeahead is not a function
}

//works
addForm(); //Adds the form
typeaheadInitialize();

//doesn't work
$('#add-contact').on('click', function(){
    addForm(); //Adds the form (this works as expected)
    typeaheadInitialize(); //Causes the error
});

Solution

  • I managed to get it working. The typeahead attribute is defined in the global scope, but doesn't follow into the scope of the callback functions. So I had to manually include it using closure:

    var typeahead = $.fn.typeahead; // get the typeahead method
    
    function typeaheadInitialize(){
      engine = new Bloodhound({
        remote: {
          url: '/api/query_expert_by_email/*',
          wildcard: '*',
          transform: function (response) {
            return response.email;
          }
        },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        datumTokenizer: Bloodhound.tokenizers.whitespace,
      });
      var typeaheadTarget = $('.typeahead');
      typeAheadTarget["typeahead"] = typeahead; // add the method to the selected input
      typeaheadTarget.typeahead(null, {
      name: 'my-dataset',
      source: engine
    });
    }