Twitter Bootstrap Typeahead Ajax 示例

285

我正在尝试查找可工作的Twitter Bootstrap补全示例,该示例将进行Ajax调用以填充其下拉菜单。

我已经有一个现有的jQuery自动完成示例,其中定义了Ajax URL以及如何处理响应。

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
    var options = { minChars:3, max:20 };
    $("#runnerquery").autocomplete('./index/runnerfilter/format/html',options).result(
            function(event, data, formatted)
                {
                    window.location = "./runner/index/id/"+data[1];
                }
            );
       ..

我需要做哪些更改才能将它转换为typeahead示例?

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
    var options = { source:'/index/runnerfilter/format/html', items:5 };
    $("#runnerquery").typeahead(options).result(
            function(event, data, formatted)
                {
                    window.location = "./runner/index/id/"+data[1];
                }
            );
       ..

我要等待 'Add remote sources support for typeahead' 这个问题得到解决。


更具体地说,我想知道自动完成选项和结果处理函数如何映射到textahead选项?是否有一组定义的textalert结果处理函数可以被覆盖,或者这些方法名称是从底层的jquery api继承而来的? - emeraldjava
1
请问您现在可以将Stijn Van Bael的回答标记为正确答案吗?bogert的答案只适用于过时版本的Bootstrap。 - Giles Roberts
17个回答

304

编辑:typeahead不再捆绑在Bootstrap 3中。请查看:

自Bootstrap 2.1.0到2.3.2以来,您可以这样做:

$('.typeahead').typeahead({
    source: function (query, process) {
        return $.get('/typeahead', { query: query }, function (data) {
            return process(data.options);
        });
    }
});

要消费像这样的JSON数据:

{
    "options": [
        "Option 1",
        "Option 2",
        "Option 3",
        "Option 4",
        "Option 5"
    ]
}

请注意,JSON数据必须是正确的 MIME 类型(application/json),这样 jQuery 才能识别它为 JSON。


3
在 Typeahead 的分支中,数据必须是一个字符串的 JSON 数组,内容类型必须是 application/json。 - Stijn Van Bael
9
2.1版本的使用JSON是否只能是字符串数组?我需要向用户显示一个值,并使用ID进行进一步处理。这是否可能而不需要使用自定义分支? - Anton
2
@Stijin 这里有没有关于如何使用匿名函数来处理显示选项的id的示例?谢谢! - Acyra
1
我想指出使用这种方法会导致在输入框中的每次按键都会发起一个 AJAX 请求。如果服务器返回的是基本静态数据(即查询结果没有被实际处理),那么这样做可能会非常浪费资源。 - Dologan
2
为什么要使用 get 而不是 getJSON?似乎更合适。 - greg0ire
显示剩余8条评论

118

您可以使用 BS Typeahead fork 来支持 ajax 调用。 然后您就可以写:

$('.typeahead').typeahead({
    source: function (typeahead, query) {
        return $.get('/typeahead', { query: query }, function (data) {
            return typeahead.process(data);
        });
    }
});

1
当我返回例如["aardvark", "apple"]时,jQuery对POST数据的“智能猜测”返回类型无法正常工作。我必须在$.post调用中显式设置dataType参数。请参阅jQuery.post() - Rusty Fausak
1
@rfausak 或者,将 Content-type 头设置为 application/json - Rusty Fausak
23
我遇到了一个未捕获的类型错误:Cannot call method 'toLowerCase' of undefined。 - Krishna Prasad Varma
我认为异步调用应该是$.getJSON。 - Tony
8
好的回答!我会使用GET请求,以符合REST标准。 - Mauro
显示剩余4条评论

71

从Bootstrap 2.1.0开始:

HTML:

<input type='text' class='ajax-typeahead' data-link='your-json-link' />

Javascript:


JavaScript:
$('.ajax-typeahead').typeahead({
    source: function(query, process) {
        return $.ajax({
            url: $(this)[0].$element[0].dataset.link,
            type: 'get',
            data: {query: query},
            dataType: 'json',
            success: function(json) {
                return typeof json.options == 'undefined' ? false : process(json.options);
            }
        });
    }
});

现在您可以创建一个统一的代码,将“json-request”链接放置在您的HTML代码中。


11
我会将其更改为使用 $(this)[0].$element.data('link') - Andrew Ellis
或者 this.$element.data('link') - Richard87

54

所有的回复都是关于Bootstrap 2的typeahead,而在Bootstrap 3中已经不再存在。

对于其他人想要使用新的Bootstrap后Twitter typeahead.js来进行AJAX示例的,请看这个可行的例子。语法略有不同:

$('#mytextquery').typeahead({
  hint: true,
  highlight: true,
  minLength: 1
},
{
  limit: 12,
  async: true,
  source: function (query, processSync, processAsync) {
    processSync(['This suggestion appears immediately', 'This one too']);
    return $.ajax({
      url: "/ajax/myfilter.php", 
      type: 'GET',
      data: {query: query},
      dataType: 'json',
      success: function (json) {
        // in this example, json is simply an array of strings
        return processAsync(json);
      }
    });
  }
});

这个例子同时使用了同步(调用 processSync)和异步建议,所以你会看到一些选项立即出现,然后添加其他选项。你可以只使用其中一个。

有很多可绑定的事件和一些非常强大的选项,包括使用对象而不是字符串工作,此时您将使用自己的自定义display函数将项目呈现为文本。


1
谢谢。还有一个问题:使用processAsync时,我得到了“TypeError: suggestions.slice不是一个函数”的错误。返回的JSON应该是什么样子的?这是我最好的猜测:{:suggestions => ["Thing 1","Thing 2","Thing 3"]}。 - user1515295
1
请确保返回一个有效的JSON字符串。你的AJAX建议函数应该返回一个字符串数组,例如["Thing 1","Thing 2"],或者使用自定义显示函数,根据你的需求返回一个对象数组,例如[{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}] - Jonathan Lidbeck
我返回了 [{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}],现在我想在typeahead下拉框中显示两列,分别是id和label。我该怎么做? - Vishal
3
哇!我已经搜索了三天,没有人提到过这个。直到现在我一直在测试同步功能。谢谢,伙计! - Gilson PJ
谢谢!在Bootstrap 4.3和jQuery 3.4下运行得非常好。但是,当鼠标悬停在列表选项上时,它们并没有被突出显示。我以为这应该是typeahead本身的一部分。 - Binita Bharati

24

我已经使用ajax增强了原始的Bootstrap自动完成插件。使用起来非常简单:

$("#ajax-typeahead").typeahead({
     ajax: "/path/to/source"
});

这是 github 仓库链接:Ajax-Typeahead


我已经查看了Gudbergur的代码;坦白地说,我最喜欢这个。它更为友好并且提供了更多的功能。干得好Paul!唯一我要建议的是在你的README中提醒用户他们需要将JSON数据解析成JS,以便您的代码能够正确使用它。我本来以为你会为我解析它,所以卡了我一下。除此之外,非常不错,谢谢!:) - Bane
3
您的服务器返回了一个字符串而不是 JSON 对象。使用 jQuery 的 $.ajax() 进行调用,并且它会处理解析。 - Paul Warelis
1
非常正确,感谢您的发现! :) 这个插件运行得非常好。 - Bane
你好,服务器端的 JSON 应该长什么样子?我遇到了 Uncaught TypeError: Cannot read property 'length' of undefined 的问题。我正在使用 json_encode($array) 并发送正确的头信息 ('Content-Type: application/json; charset=utf-8')。jQuery 版本为 jQuery v1.9.1 - Kyslik

5

我对jquery-ui.min.js进行了一些修改:

//Line 319 ORIG:
this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(...
// NEW:
this.menu=d("<ul></ul>").addClass("ui-autocomplete").addClass("typeahead").addClass("dropdown-menu").appendTo(d(...

// Line 328 ORIG:
this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr...
// NEW:this.element.attr....

// Line 329 ORIG:
this.active=a.eq(0).children("a")
this.active.children("a")
// NEW:
this.active=a.eq(0).addClass("active").children("a")
this.active.removeClass("active").children("a")`

并添加以下CSS
.dropdown-menu {
    max-width: 920px;
}
.ui-menu-item {
    cursor: pointer;        
}

功能完美。


你使用的是哪个版本的jQuery UI min文件? - emeraldjava
如果您需要适用于jQuery 1.7.1和jQuery UI 1.8.16的内容,则我基于上述修复创建了一个GIST,其中显示了更改jQuery UI文件的位置。https://gist.github.com/1884819 - 注释行以//modified开头。 - RidingTheRails
这是一个相当老的问题/答案,但我想说的是,更改第三方组件代码总是一种不好的做法。每次升级它们时,您都必须重新审查所有更改。在这种特殊情况下,jQuery小部件可以被继承,这是一种更安全的自定义方式。因此,基本上,创建自己的小部件,从核心小部件(在这种情况下为自动完成)继承,并释放您的想象力! :) - AlexCode

2

我正在使用这种方法

$('.typeahead').typeahead({
    hint: true,
    highlight: true,
    minLength: 1
},
    {
    name: 'options',
    displayKey: 'value',
    source: function (query, process) {
        return $.get('/weather/searchCity/?q=%QUERY', { query: query }, function (data) {
            var matches = [];
            $.each(data, function(i, str) {
                matches.push({ value: str });
            });
            return process(matches);

        },'json');
    }
});

如果您能在回答中添加一些解释,那就太好了。例如,您的解决方案与已有答案中呈现的解决方案有何不同之处? - honk

2
可以使用 Bootstrap 进行电话呼叫。当前版本没有任何源更新问题(使用帖子响应更新 Bootstrap 的类型提示数据源时出现问题),即一旦更新了 bootstrap 的源代码,就可以再次修改它。
请参考下面的示例:
jQuery('#help').typeahead({
    source : function(query, process) {
        jQuery.ajax({
            url : "urltobefetched",
            type : 'GET',
            data : {
                "query" : query
            },
            dataType : 'json',
            success : function(json) {
                process(json);
            }
        });
    },
    minLength : 1,
});

2
如果您的服务没有返回正确的应用程序/json内容类型标头,请尝试以下方法:
$('.typeahead').typeahead({
    source: function (query, process) {
        return $.get('/typeahead', { query: query }, function (data) {
            var json = JSON.parse(data); // string to json
            return process(json.options);
        });
    }
});

1

我没有一个可工作的示例给你,也没有一个非常干净的解决方案,但让我告诉你我发现了什么。

如果你查看TypeAhead的JavaScript代码,它看起来像这样:

items = $.grep(this.source, function (item) {
    if (that.matcher(item)) return item
  })

这段代码使用 jQuery 的 "grep" 方法来匹配源数组中的元素。我没有看到任何可以挂载 AJAX 调用的地方,所以没有一个“完美”的解决方案。

然而,你可以利用 jQuery 中 "grep" 方法工作方式的某种 hacky 方式来解决这个问题。grep 的第一个参数是源数组,第二个参数是用于匹配源数组的函数(注意 Bootstrap 在初始化时调用了你提供的 "matcher" 函数)。你可以将源设置为一个虚拟单元素数组,并将匹配器定义为一个带有 AJAX 调用的函数。这样,它只会运行一次 AJAX 调用(因为你的源数组只有一个元素)。

这个解决方案不仅 hacky,而且会受到性能问题的影响,因为 TypeAhead 代码设计为在每次按键时进行查找(AJAX 调用应该只在每隔几个按键或一定量的空闲时间后发生)。我的建议是尝试一下,但如果遇到任何问题,要么选择其他自动完成库,要么只在非 AJAX 情况下使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接