Handling objects with Twitter Bootstrap Typeahead

23,260

Solution 1

After searching around a bit on the net I found this HowTo. In it they do what you want, but with no ajax.

You should also be able to return a object, from the source function, but you would need to re-implement all the helper functions of typeahead.

Solution 2

You cannot normally use JSON objects directly within Bootstrap Typeahead (2.x), but you can easily tweak it to do so. The wording of this question should help for people to find this in one place. Other questions have asked similar things, but not identical to the way that you did.

var typeahead = control.typeahead({ /* ... */ }).data('typeahead');

// manually override select and render
//  (change attr('data-value' ...) to data('value' ...))
//  otherwise both functions are exact copies
typeahead.select = function() {
    var val = this.$menu.find('.active').data('value')
    this.$element.val(this.updater(val)).change()
    return this.hide()
};
typeahead.render = function(items) {
    var that = this

    items = $(items).map(function (i, item) {
        i = $(that.options.item).data('value', item)
        i.find('a').html(that.highlighter(item))
        return i[0]
    });

    items.first().addClass('active')
    this.$menu.html(items)
    return this
};

Other than that, you must override highlighter, matcher, sorter, and updater, but those can done via the options passed into the typeahead, where the passed in item(s) are now your JSON objects.

When selecting items, updater is called, which is how you set the value and use the JSON data:

updater: function (item) {
    someGlobalValue = item.id;

    // must return a normal string; sets the textbox value
    return item.name;
}

This also means that you don't need to do anything fancy to associate, or otherwise "remember" the items external to Typeahead referenced example in the other answer. The most annoying part of the whole overriding process is rewriting the sorter in every use.

Solution 3

I have an ugly solution...

I needed to be able to search into the title but to finally put the ID into the text input...

my JSON is

[
{"id": 1, "title": "Foo foo foo"},
{"id": 2, "title": "Bar bar bar"},
...
]

and my call...

$(function() {
    $.get("path/to/data.json", function(data){
          $(".typeahead").typeahead({
              "source": data,
              "displayText": function(item){
                  // OMG ugly !!! :p
                  if (item.id == undefined) return item;
                  return item.title + ' (' + item.id + ')';  
              },
              "updater": function(item) {
                  return item.id;
              }});
    }, 'json');
});

All is working as usual but when you click on the selected item, only the id is put into the field...

done ! ugly but done...

Tested with https://github.com/bassjobsen/Bootstrap-3-Typeahead

Share:
23,260
Cameron
Author by

Cameron

Updated on October 29, 2020

Comments

  • Cameron
    Cameron over 3 years

    I'm using the Bootstrap Typeahead plugin like so:

    $('#Organisation').typeahead({
                source: function (query, process) {
                    return $.get(AppURL + 'Organisations/Manage/SearchByName/',
                    {
                        term: query
                    },
                    function (data) {
                        var results = [];
                        var fullResults = [];
                        $.each(data, function (index, item) {
                            results.push(item.label);
                            fullResults.push({
                                id: item.ID,
                                label: item.label
                            });
                        });
    
                        return process(results);
    
    
                    });
                },
                updater: function (selection) {
                    $('#OrganisationID').val(selection);
                }
            });
    

    I have two returned arrays, this is because Typeahead ONLY wants a list of strings instead of an object. The second array contains both the label and id.

    Once a user selects an item from the list I need to get the ID from this selection and then use it to insert into a hidden field. But the selection will just be the name, as the ID can't be passed through via Typeahead.

    Any ideas on how I can solve this?

    An example of the two returned arrays:

    results: ["Organisation 1","Organisation 2"]

    fullResults: [{"label":"Organisation 1","ID":2},{"label":"Organisation 2","ID":1}]