Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend the bootstrap-typeahead in order to take an object instead of a string

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;
        }
    });
};
like image 584
Lorraine Bernard Avatar asked Aug 29 '12 16:08

Lorraine Bernard


1 Answers

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/

like image 64
antonjs Avatar answered Sep 25 '22 15:09

antonjs