Using Twitter Bootstrap Typeahead to select a key/value pair, not a string

Twitter Bootstrap comes with a UI widget called Typeahead — an auto-complete textbox. Problem is, it works only with strings — you type a string, it searches a list of strings, when you choose one, it tells you you selected a string.

This is fine in some cases, but it’s not much cop if you want to select, say, a primary key field.

I’ve found an approach for this that lets you select in a more traditional manner — search names, return a different, unique value. It uses the ‘highlighter’ function and a little bit of JSON. Highlighter is a bit of a misnomer — it’s actually an arbitrary function for re-writing the text that appears in the dropdown.

So when you invoke, say, $(‘#mysearchbox’).typeahead(), you pass a set of options. Here’s what you need to do for each option;

source: Set the source option to a function returning an array of JSON-serialized name/value pairs;

return [
JSON.stringify({ name:”one”, value: 1 }},

    JSON.stringify({ name:”two”, value: 2 }},

    JSON.stringify({ name:”three”, value: 3 }},

    JSON.stringify({ name:”four”, value: 4 }},

    JSON.stringify({ name:”five”, value: 5 }}

];

highlighter: Set the highlighter to return just the name, not the value;

highlighter: function(item) {
return JSON.parse(item).name;
}

matcher: Set the matcher to return things that match the right name;

matcher: function (item) {
return

      JSON.parse(item).name.toLocaleLowerCase()

      .indexOf(this.query.toLocaleLowerCase()) != -1;
}

updater: Use the updater to catch the selected item;

updater: function (item) {
alert(JSON.parse(item).value);
return JSON.parse(item).name;
}

This pattern lets you search for text but return a corresponding key.

Advertisement

8 thoughts on “Using Twitter Bootstrap Typeahead to select a key/value pair, not a string

      • Hey Steve
        The json obj is incorrectly formatted, it has the wrong closing brackets ({…}} , also you dont need to use JSON.parse, this seems to work with your example:
        return [{ name:”one”, value: 1 },{ name:”two”, value: 2 },{ name:”three”, value: 3 },{ name:”four”, value: 4 },{ name:”five”, value: 5 }];
        Thanks for this code!

  1. This post was a great help to me! You can skip all the JSON stuff, though. Just work with your IDs the entire time, like this:

    var objects = {
    1: { name: ‘one’ }
    2: { name: ‘two’ }
    }

    source: [1, 2, 3, 4 5],
    highlighter: function(id) {
    return objects[id]
    },
    matcher: function(id) {
    return objects[id].toLocaleLowerCase().indexOf(
    this.query.toLocaleLowerCase()) != -1
    },
    updater: function(id) {
    alert(id)
    return object[id]
    }

  2. This post was a great help to me. Thanks! You can simplify things by removing all the JSON calls, though. For example:

    var objects = {
    1: { name: ‘one’ }
    2: { name: ‘two’ }
    }

    source: [1, 2, 3, 4 5],
    highlighter: function(id) {
    return objects[id]
    },
    matcher: function(id) {
    return objects[id].toLocaleLowerCase().indexOf(
    this.query.toLocaleLowerCase()) != -1
    },
    updater: function(id) {
    alert(id)
    return object[id]
    }

  3. i was working on typeahead for the first time and stumbled upon the very same problem…
    i solved it the following way.
    in the dropdown I can show the name as “Lname, Fname” by using following
    ng-model=”$scope.selected” uib-typeahead=”name as name.lname+’,’+name.fname for name in getMembers($viewValue)

    the raw individula json object is reflected in the model $scope.selected.
    using $scope.selected.id – I can get the unique id.

    Hope this helps.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s