How do I add typeahead.js (Bloodhound) to jQuery dynamically-created fields?

I can load Twitter typeahead just fine on a static form. However, in this situation, I would like to apply it to a dynamically-generated field. Even though my duplication script adds the required ".typeahead" class to the new input, it never seems to work. Indeed, the static form is surrounded by several additional classes, which are not generated for the dynamic fields.

I feel like there is something more I need to do in order for the dynamic fields to function like the static field, but I am not sure.

The Javascript:

<!-- Dataset: First Names -->
var firstnames = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    prefetch: {
        url: './datasets/firstnames.json',
        filter: function(list) {
            return $.map(list, function(firstname) { return { name: firstname }; });
        }
    }
});

firstnames.initialize();

$('.typeahead').typeahead(null, {
    name: 'firstnames',
    displayKey: 'name',
    source: firstnames.ttAdapter()
});
<!-- Dataset: First Names (End) -->

<!-- Dynamic Fields -->
var count=2;
$("#add").click(function(){
    var html="<div id='div"+count+"'><input id='firstname"+count+"' type='text' class='typeahead' placeholder='Additional First Name'></input><button type='button' onclick=remover('"+count+"')>Remove</button></div>";
$("#additionalnames").append(html);

    count++;
});

function remover(which){
  $("#div"+which).remove();
}
<!-- Dynamic Fields End -->

The HTML:

<p>Standard field works fine (type a letter from a to g):</p>
<input type="text" id="firstname" name="firstname" class="typeahead" placeholder="First Name">
<br /><br /><br /><br /><br /><br />
<p>Dynamic field does not:</p>
<div id="additionalnames"></div>
<button id="add" type="button">Add Another</button>

I don't think JSFiddle can handle my json file, so a live implementation is here: http://drjoeseriani.com/firstnames

A downloadable version of this resides here: http://drjoeseriani.com/firstnames.zip

Thanks for any help.

Upvotes: 0

Views: 1242

Answers (1)

Dhiraj
Dhiraj

Reputation: 33618

Creating elements using javascript instead of appending raw markup can be useful. Why ?

Because if you create an element using javascript (or jQuery), you can attach an event/plugins to it and in this case it can be a typeahead plugin.

Like this

var input = $('<input>').attr('id', 'firstname' + count).addClass('typeahead').prop('placeholder', 'Additional First Name');

Now that you have an input element you can attach .typehead({ ... }) to it.

So your click event should be something like this.

$("#add").click(function() {
  // creating a new <div id=count></div>
  var div = $('<div>').attr('id', count);

  // creating a new <input id=count class="typeahead" placeholder=".."></input> 
  var input = $('<input>').attr('id', 'firstname' + count)
    .addClass('typeahead')
    .prop('placeholder', 'Additional First Name');

  // creating a new <button>Remove</button> (with a click event)
  var button = $('<button>').text('Remove')
    .on('click', function() {
      $(this).closest('div').remove();
    });

  div.append(input); // appending the input to the div
  div.append(button); // appending the button to div

  // attaching typeahead to the newly creating input
  input.typeahead(null, {
    name: 'firstnames',
    displayKey: 'name',
    source: firstnames.ttAdapter()
  });

  // appending our newly creating div with all the element inside to #additionalnames
  $("#additionalnames").append(div);

  // incrementing count
  count++;
});

Also, I changed the took the liberty of removing the remover script all together. You can attach a click event to the button and look for the parent div and remove it using .closest()

Hope this helps.

Upvotes: 1

Related Questions