Twitter Bootstrap Typeahead - Id & Label

70,561

Solution 1

There's a great tutorial here that explains how to do this: http://tatiyants.com/how-to-use-json-objects-with-twitter-bootstrap-typeahead/ (read my comment on that page if it hasn't been reflected yet in the main part of the post).

Based on that tutorial, and the JSON you provided, you can do something like this:

$(':input.autocomplete').typeahead({
    source: function(query, process) {
        objects = [];
        map = {};
        var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable
        $.each(data, function(i, object) {
            map[object.label] = object;
            objects.push(object.label);
        });
        process(objects);
    },
    updater: function(item) {
        $('hiddenInputElement').val(map[item].id);
        return item;
    }
});                    

Solution 2

As of version 0.10.1 of Twitter Typeahead (https://github.com/twitter/typeahead.js), Id / Label is supported natively:

  $('input[name=address]').typeahead({
        hint: false
    }, {
        source: function (query, cb) {
            $.ajax({
                url: '/api/addresses?q=' + encodeURIComponent(query),
                dataType: 'json',
                cache: false,
                type: 'GET',
                success: function (response, textStatus, jqXHR) {
                    cb(response.data);
                },
                error: function (jqXHR, textStatus, errorThrown) {
                }
            });
        },
        name: 'addresses',
        displayKey: 'text'
    }).on('typeahead:selected', function (e, suggestion, name) {
        window.location.href = '/' + suggestion.id;
    });

If the example above, I'm passing an array of objects to the source callback (cb). By specifying displayKey: 'text', I'm telling the library to use the 'text' property for the auto-suggest. When the 'typeahead:select' callback is called, the second argument passed in (suggestion) contains the object that was selected.

Solution 3

To clarify what I was saying in my comment. If you wanted multiple type aheads on the same page you need to define each in a function and create a separate map variable for them.

function initFromField() {
    var map;
    $('#from:input.autocomplete').typeahead({
        source: function(query, process) {
            map = {};
            var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable
            objects = constructMap(data, map);
            process(objects);
        },
        updater: function(item) {
            $('#hidden-from-input').val(map[item].id);
            return item;
        }
    });
}

function initToField() {
    var map;
    $('#to:input.autocomplete').typeahead({
        source: function(query, process) {
            objects = [];
            map = {};
            var data = [{"id":1,"label":"machin"},{"id":2,"label":"truc"}] // Or get your JSON dynamically and load it into this variable
            objects = constructMap(data, map);
            process(objects);
        },
        updater: function(item) {
            $('#hidden-to-input').val(map[item].id);
            return item;
        }
    });
}

function constructMap(data, map) {
    var objects = [];
    $.each(data, function(i, object) {
        map[object.label] = object;
        objects.push(object.label);
    });
    return objects;
}

$(function initFields() {
    initFromField();
    initToField();
});

Note how I scoped the map variable inside the two field initialization functions. This is important, it makes sure the same map variable is not used by both input fields.

Solution 4

I've been struggling with this problem myself, here is the solution I came up with, for data of the type:

[{'id':an_id, 'name':a_name}]

Was:

$("#memberSearch").typeahead({
            source: function (query, process) {
                var $this = this //get a reference to the typeahead object
                return $.get('/getSwimmerListJSON',function(data){
                    var options = [];
                    $this["map"] = {}; //replace any existing map attr with an empty object
                    $.each(data,function (i,val){
                        options.push(val.name);
                        $this.map[val.name] = val.id; //keep reference from name -> id
                    });
                    return process(options);
                });
            },
            updater: function (item) {
                console.log(this.map[item],item); //access it here

            }

        });

Solution 5

Here is an encapsulated solution. This solution allows you have more than one typeahead on the same page.

This is a modified version of #13279176 Gerbus answer.

$('.make-me-typeahead').typeahead({
    source: function (query) {
        var self = this;
        self.map = {};
        var items = [];

        var data = [
            {"id": 1, "label": "machin"},
            {"id": 2, "label": "truc"}
        ];

        $.each(data, function (i, item) {
            self.map[item.label] = item;
            items.push(item.label)
        });

        return items;
    },

    updater: function (item) {
        var selectedItem = this.map[item];
        this.$element.data('selected', selectedItem);
        return item;
    }
});

Now when you need get the key of the current selected item you just need do $('.make-me-typeahead').data('selected')

Share:
70,561

Related videos on Youtube

Pierre de LESPINAY
Author by

Pierre de LESPINAY

Web developer at Masao. Fan of Django/python, Symfony/php, Vue/javascript, Docker EPITECH promo 2004.

Updated on July 09, 2022

Comments

  • Pierre de LESPINAY
    Pierre de LESPINAY almost 2 years

    I'm using Bootstrap 2.1.1 and jQuery 1.8.1 and trying to use Typeahead's functionality.

    I try to display a label and use an id like a standard <select />

    Here is my typeahead initialization:

    $(':input.autocomplete').typeahead({
        source: function (query, process) {
            $('#autocompleteForm .query').val(query);
            return $.get(
                $('#autocompleteForm').attr('action')
              , $('#autocompleteForm').serialize()
              , function (data) {
                  return process(data);
              }
            );
        }
    });
    

    Here is the kind of JSON that I'm sending

    [{"id":1,"label":"machin"},{"id":2,"label":"truc"}]
    

    How can I tell process() to display my labels and store the selected ID in another hidden field?

  • Michael Yagudaev
    Michael Yagudaev about 11 years
    one important thing to note is the map variable there and its scope. According to your code it is global together with the objects variable. This mean that you can only have 1 typeahead on the page at a time, otherwise the map object will be shared between typeahead boxes and lead to weird bugs. To have multiple type a heads you will need to use a closure and define the map variable there.
  • yayitswei
    yayitswei almost 11 years
    "Names of your objects need to be unique for this to work." So, their solution doesn't work if you're, say, filtering a list of people who might have the same name.
  • Derek Nutile
    Derek Nutile over 10 years
    Twitter Bootstrap has a new path on Github. Try github.com/twbs/bootstrap/pull/3682
  • Marcel Burkhard
    Marcel Burkhard almost 10 years
    @yayitswei That would be pointless anyway, as the user wouldn't be able to identify which entry is the right one.
  • yayitswei
    yayitswei over 9 years
    @MarcelBurkhard you could have other elements in the dropdown item to identify the entry, e.g. a facebook picture based on the id.
  • elplatt
    elplatt over 9 years
    I would be interested to see how this can be done if you're using the Bloodhound engine.
  • anweibel
    anweibel about 9 years
    This plugin worked very well for me with Bootstrap 3: github.com/bassjobsen/Bootstrap-3-Typeahead
  • Mike Castro Demaria
    Mike Castro Demaria about 9 years
    +1 : you can use the same process if you need more data, like fill many fields with 1 select. Just add more data in the json and in the "updater" duplicate the val() action.
  • Demetris Leptos
    Demetris Leptos almost 7 years
    but what about same display text entries?
  • Demetris Leptos
    Demetris Leptos almost 7 years
    in bootstrap-typeahead: displayText function option - finally - no need for maps
  • Vahid Amiri
    Vahid Amiri over 6 years
    This is da answer.
  • makat
    makat about 3 years
    doesn't seem to work with this code - anyone able to get it working?