I extended the bootstrap-typeahead in order to take an object instead of a string.
It works but I would like to know this is the right way to do the things.
Thanks.
Reference:
http://twitter.github.com/bootstrap/javascript.html#typeahead
http://twitter.github.com/bootstrap/assets/js/bootstrap-typeahead.js
_.extend($.fn.typeahead.Constructor.prototype, {
render: function (items) {
var that = this;
items = $(items).map(function (i, item) {
i = $(that.options.item)
.attr('data-value', item[that.options.display])
.attr('data-id', item.id);
i.find('a').html(that.highlighter(item));
return i[0];
});
items.first().addClass('active');
this.$menu.html(items);
return this;
},
select: function () {
var val = this.$menu.find('.active').attr('data-value'),
id = this.$menu.find('.active').attr('data-id');
this.$element
.val(this.updater(val, id))
.change();
return this.hide()
}
});
return function (element, options) {
var getSource = function () {
return {
id: 2,
full_name: 'first_name last_name'
};
};
element.typeahead({
minLength: 3,
source: getSource,
display: 'full_name',
sorter: function (items) {
var beginswith = [],
caseSensitive = [],
caseInsensitive = [],
item,
itemDisplayed;
while (item = items.shift()) {
itemDisplayed = item[this.options.display];
if (!itemDisplayed.toLowerCase().indexOf(this.query.toLowerCase())) {
beginswith.push(item);
} else if (~itemDisplayed.indexOf(this.query)) {
caseSensitive.push(item);
} else {
caseInsensitive.push(item);
}
}
return beginswith.concat(caseSensitive, caseInsensitive);
},
highlighter: function (item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
return item[this.options.display].replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>';
});
},
matcher: function (item) {
var value = item[this.options.display];
return {
value: ~value.toLowerCase().indexOf(this.query.toLowerCase()),
id: item.id
};
},
updater: function (item, userId) {
options.hiddenInputElement.val(userId);
return item;
}
});
};
I recommend to not rewrite the prototype (which would impact all places where you could use the autocompleter, not only the following function).
This code should work:
var getSource = function () {
var users = new Backbone.Collection([
{
first_name: 'primo',
last_name: 'ultimo',
id: 1
},
{
first_name: 'altro_primo',
last_name: 'altro_ultimo',
id: 2
}
]).models;
return _.map(users, function (user) {
return {
id: user.get('id'),
full_name: user.get('first_name') + ' ' + user.get('last_name'),
// these functions allows Bootstrap typehead to use this item in places where it was expecting a string
toString: function () {
return JSON.stringify(this);
},
toLowerCase: function () {
return this.full_name.toLowerCase();
},
indexOf: function (string) {
return String.prototype.indexOf.apply(this.full_name, arguments);
},
replace: function (string) {
return String.prototype.replace.apply(this.full_name, arguments);
}
};
});
};
$('.full_name').typeahead({
minLength: 3,
source: getSource(),
display: 'full_name',
updater: function (itemString) {
var item = JSON.parse(itemString);
$('.id').val(item.id);
return item.full_name;
}
});
demo: http://jsfiddle.net/hyxMh/48/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With