diff --git a/docs/templates/pages/javascript.mustache b/docs/templates/pages/javascript.mustache index 26ca9b538..7e0fdd858 100644 --- a/docs/templates/pages/javascript.mustache +++ b/docs/templates/pages/javascript.mustache @@ -1376,9 +1376,9 @@ $('.carousel').carousel({ {{_i}}source{{/i}} - {{_i}}array{{/i}} + {{_i}}array, function{{/i}} [ ] - {{_i}}The data source to query against.{{/i}} + {{_i}}The data source to query against. May be an array of strings or a function. The function is passed two arguments, the query value in the input field and the process callback. The function may be used synchronously by returning the data source directly or asynchronously via the process callback's single argument.{{/i}} {{_i}}items{{/i}} @@ -1417,4 +1417,4 @@ $('.carousel').carousel({

{{_i}}Initializes an input with a typeahead.{{/i}}

- \ No newline at end of file + diff --git a/js/bootstrap-typeahead.js b/js/bootstrap-typeahead.js index e5197a331..6e896bb98 100644 --- a/js/bootstrap-typeahead.js +++ b/js/bootstrap-typeahead.js @@ -77,9 +77,7 @@ } , lookup: function (event) { - var that = this - , items - , q + var items this.query = this.$element.val() @@ -87,7 +85,15 @@ return this.shown ? this.hide() : this } - items = $.grep(this.source, function (item) { + items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source + + return items ? this.process(items) : this + } + + , process: function (items) { + var that = this + + items = $.grep(items, function (item) { return that.matcher(item) }) @@ -290,4 +296,4 @@ }) }) -}(window.jQuery); \ No newline at end of file +}(window.jQuery); diff --git a/js/tests/unit/bootstrap-typeahead.js b/js/tests/unit/bootstrap-typeahead.js index 4e2428d6a..25d4cafd8 100644 --- a/js/tests/unit/bootstrap-typeahead.js +++ b/js/tests/unit/bootstrap-typeahead.js @@ -52,6 +52,42 @@ $(function () { typeahead.$menu.remove() }) + test("should accept data source via synchronous function", function () { + var $input = $('').typeahead({ + source: function () { + return ['aa', 'ab', 'ac'] + } + }) + , typeahead = $input.data('typeahead') + + $input.val('a') + typeahead.lookup() + + ok(typeahead.$menu.is(":visible"), 'typeahead is visible') + equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu') + equals(typeahead.$menu.find('.active').length, 1, 'one item is active') + + typeahead.$menu.remove() + }) + + test("should accept data source via asynchronous function", function () { + var $input = $('').typeahead({ + source: function (query, process) { + process(['aa', 'ab', 'ac']) + } + }) + , typeahead = $input.data('typeahead') + + $input.val('a') + typeahead.lookup() + + ok(typeahead.$menu.is(":visible"), 'typeahead is visible') + equals(typeahead.$menu.find('li').length, 3, 'has 3 items in menu') + equals(typeahead.$menu.find('.active').length, 1, 'one item is active') + + typeahead.$menu.remove() + }) + test("should not explode when regex chars are entered", function () { var $input = $('').typeahead({ source: ['aa', 'ab', 'ac', 'mdo*', 'fat+']