使用Typeahead时,可以使用JSON数据中不同的值代替displayKey。

30

我开始使用Typeahead.js,但是很难想出一种让用户输入并搜索公司名称的方法,一旦选择了公司名称,就能够输入相关的公司代码。

.json文件:

[{
    "company_name": "Facebook",
    "code": "fb",
}, {
    "company_name": "Google",
    "code": "goog",
}, {
    "company_name": "Yahoo",
    "code": "yhoo",
}, {
    "company_name": "Apple",
    "code": "aapl",
}, {
    "company_name": "Royal Mail",
    "code": "rmg.l",
}]

.js脚本:

var stocks = new Bloodhound({
    datumTokenizer: function(d) {
        return Bloodhound.tokenizers.whitespace(d.code);
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 3,
    prefetch: {
        url: 'javascripts/stockCodes.json',
        filter: function(list) {
            return $.map(list, function(stock) {
                return {
                    code: stock
                };
            });
        }
    }
});

stocks.initialize();

$('.typeahead').typeahead(null, {
    name: 'stocks',
    displayKey: 'code',
    source: stocks.ttAdapter()
});

目前,当用户在输入框中输入时,它只会显示代码列表。但是,我想知道是否有一种方法可以让他们搜索code,但一旦选择,文本框中的值为company_name?是否可以使用此插件实现这一点。非常感谢您的任何帮助。

谢谢!


你能否改变你的数据结构? - Tomanow
@Tomanow 当然可以。我只是认为这种结构会更有效率。谢谢。 - user1779796
我刚刚更新了我的答案。现在应该更准确了。 - Tomanow
6个回答

35

displayKey 用于指示在用户选择条目后,应在下拉列表和输入字段中显示哪个键。

如果您希望下拉列表中显示的条目与最终显示在输入字段中的不同,则需要使用自定义模板。

来自文档

suggestion - 用于呈现单个建议。 如果设置了此项,则必须是一个预编译的模板。 关联的建议对象将作为上下文。 默认值为 displayKey 包装在 p 标记中,即<p> {{value}}</p>

像这样的东西应该可以起作用:

$('.typeahead').typeahead(null, {
    name: 'stocks',
    displayKey: 'company_name',
    source: stocks.ttAdapter(),
    templates: {
        suggestion: function (stock) {
            return '<p>' + stock.code + '</p>';
        }
    }
});

提交的模板将用于在下拉列表中显示stock.code,在用户选择条目后,stock.company_name将显示在输入字段中。


19

我不是jQuery / JavaScript方面的专家。因此,我更喜欢简单的方法。只是为了在以后查看我的代码时能够理解我做了什么...

感谢Eric Saupe,我找到了一个聪明的解决方案:

//JSON FILE
[
    {
        "company_name": "Facebook",
        "code": "fb",
    },
    {
        "company_name": "Google",
        "code": "goog",
    },
    {
        "company_name": "Yahoo",
        "code": "yhoo",
    },
    {
        "company_name": "Apple",
        "code": "aapl",
    },
    {
        "company_name": "Royal Mail",
        "code": "rmg.l",
    },
 ]

// JS SCRIPT

   var stocks = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('company_name'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: 'javascripts/stockCodes.json'
    });

    stocks.initialize();

    $('.typeahead').typeahead(
        null, {
        name: 'stocks',
        displayKey: 'company_name',
        source: stocks.ttAdapter()
    }).on('typeahead:selected', function(event, data){            
        $('.typeahead').val(data.code);        
    });

只需按照在github文档中描述的方式使用typeahead自定义事件即可。

希望这有所帮助(当然,仅供我以后参考时使用)。

JSFIDDLE


1
你还想处理'typeahead:autocompleted'。 - Alok
似乎是最好的解决方案,但JSFIDDLE不再起作用。 点击时,它会写下整个公司名称。 - NLemay
typeahead:selected 还是 typeahead:select?官方文档说后者。无论哪种方式,我都无法触发事件。我在你的 fiddle 中添加了 alert(data.code); 也没有触发。什么才是正确的方法? - Old Geezer
JSFIDDLE对我来说正常工作。我用Firefox和Chrome测试过了。 我无法确定是:selected还是:select。对我来说,使用:selected可以工作。 同时,我转向了jQuery Typeahead(http://www.runningcoder.org/jquerytypeahead/documentation/)。它有很好的文档和丰富的功能,并且配置更加直观(在我看来)。 - Tobse
即使使用了setTimeout方法,例如:setTimeout(function() { $('.typeahead').val(data.code); }, 1);,当离开输入框时,它仍会将值改回去。因此,我不得不采用@Esseb的基于模板的解决方案。 - Rehmat

7
你需要使用´displayKey´变量。请参考以下从typeahead文档中复制的内容:
´displayKey´ - 对于给定的建议对象,确定其字符串表示形式。在选择建议后设置输入控件的值时将使用它。可以是键字符串或将建议对象转换为字符串的函数。默认为`value`。

https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md

您的具体代码将如下所示:

var stocks = new Bloodhound({
        datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.code); },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        limit: 3,
        prefetch: {
            url: 'javascripts/stockCodes.json',
            filter: function(list) {
                // This should not be required, but I have left it incase you still need some sort of filtering on your server response
                return $.map(list, function(stock) { return { code: stock.code, company_name: stock.company_name }; });
            }
        }
    });

    stocks.initialize();

    $('.typeahead').typeahead(null, {
        name: 'stocks',
        displayKey: function(stock) {
           return stock.company_name;
        },
        source: stocks.ttAdapter()
    });

我自己的网站上也有类似的要求,我已经成功实现了这个功能,没有出现问题。不过我还没有尝试过这个具体的示例,如果它能正常工作,请告诉我。
记得调用stocks.clearPrefetchCache();来清除缓存,以便更轻松地跟踪错误。

4

如果我理解正确的话,我认为这就是你想要的:

var stocksData = [{
    "Facebook": "fb",
}, {
    "Google": "goog",
}, {
    "Yahoo": "yhoo",
}, {
    "Apple": "aapl",
}, {
    "Royal Mail": "rmg.l",
}, ];

var stocks = new Bloodhound({
    datumTokenizer: function (d) {
                  for (var prop in d) {
                      return Bloodhound.tokenizers.whitespace(d[prop]);
                  }

    },
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 3,
    local: stocksData,
});

stocks.initialize();

$('input').typeahead(null, {
    name: 'stocks',
    displayKey: function(stocks) {
        for (var prop in stocks) {
            return prop;    
        }
    },
    source: stocks.ttAdapter()
});

你肯定希望将本地更改为与 json 文件类似的预取/远程方式。
更新: 代码片段

谢谢您的回答,非常感谢。我刚刚开始使用上面提供的代码。我不确定我是否正确地解释了问题,但我正在尝试弄清楚如何将相关值放置在输入文本框中,而不是键值。例如,输入“Facebook”应该在下拉列表中显示Facebook,但是一旦选择,文本框值将显示“fb”,而不是“Facebook”。我已经尝试调整提供的代码,但还没有成功实现这个功能。谢谢您的帮助。 - user1779796

0

显示参数中添加需要显示的值:

$(".comp-search").typeahead({
    hint: true,
    highlight: true,
    minLength: 1,
    displayKey: 'company_name',
}, {
    source: engine.ttAdapter(),
    templates: {
        empty: ['<div class="list-group search-results-dropdown"><div class="list-group-item">Nothing found.</div></div>'],
        header: ['<div class="list-group search-results-dropdown">'],
        suggestion: function (data) {
            return '<a href="javascript:void(0);" class="list-group-item">' + data.company_name + '</a>';
        }
    },
    display: function(data) { return data.company_name; }
});

希望这对你有所帮助。

0

我也遇到了同样的问题,无法使用"display"或"displayKey"属性使其正常工作。通过在源对象中添加"name"属性解决了这个问题。

            $.each(stocks, function (i, item) {
                item.name = item.company_name;
            });

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