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.
Nice workaround, thanks!
Could you provide an example with an array of 5 elements? Thanks.
Hi. Just updated the main example.
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!
Excellent work. Thanks a lot 🙂
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]
}
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]
}
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.