Twitter Bootstrap Typeahead支持多值吗?

46
我正在使用Twitter Bootstrap和Jquery。我想为文本区域使用TYPEAHEAD函数,这个很容易实现。但是,我还需要它允许多次选择

我的意思是,在我从自动完成中选择一个单词后,它会在后面加上一个额外的空格,然后如果我再次开始输入,它会再次提供给我选择。

这里有一个JS bin:http://jsbin.com/ewubuk/1/edit(里面没有什么特别的东西)。

有没有简单的方法允许使用typeahead进行多次选择? 如果有,怎么做?

谢谢您提前。

5个回答

90

编辑:关于此问题已经有一个合并请求:https://github.com/twitter/bootstrap/pull/2007


您可以通过使用类型提醒的代理来实现所需的行为:演示(jsfiddle)

var $myTextarea = $('#myTextarea');

$('.typeahead').typeahead({
    source: source,
    updater: function(item) {
        $myTextarea.append(item, ' ');
        return '';
    }
});

我认为updater方法就是为了处理这种情况的,你只需要返回要显示的内容即可。


或者如果你真的想让所有东西都在同一个输入元素中,那么你需要覆盖更多的方法,以便它仅匹配当前键入的元素:演示(jsfiddle)

function extractor(query) {
    var result = /([^,]+)$/.exec(query);
    if(result && result[1])
        return result[1].trim();
    return '';
}

$('.typeahead').typeahead({
    source: source,
    updater: function(item) {
        return this.$element.val().replace(/[^,]*$/,'')+item+',';
    },
    matcher: function (item) {
      var tquery = extractor(this.query);
      if(!tquery) return false;
      return ~item.toLowerCase().indexOf(tquery.toLowerCase())
    },
    highlighter: function (item) {
      var query = extractor(this.query).replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
        return '<strong>' + match + '</strong>'
      })
    }
});

这个并不十分傻瓜化,因为你需要在特殊字符之后输入。


1
嗯,这似乎是一个很好的计划,但它不再适用于Bootstrap 2.3.1。至少对我来说是这样。更新器方法对我没有任何作用,但typehead作为单个工作。 - Glorious Kale
好的,我错过了HTML部分。我放置了<input type="text" data-provide="typeahead" />而不是<input type="text" class="typeahead" /> - Glorious Kale
2
@IvanIvković 如果你遇到问题,你应该尝试在类似 jsfiddle 的网站上调试并提出一个新的问题(参考这个问题)。但是我看到你已经解决了问题,太好了! - Sherbrow
@AtaS。此插件已从twbs中删除。请检查您正在使用的版本,如果您正在使用[typeahead.js](http://twitter.github.io/typeahead.js/),则应仅查找与该插件相关的文档/问题。 - Sherbrow
有没有办法让它像使用ctrl + 单击一样选择多个项目? - lucentx
显示剩余7条评论

14

2
仅供参考,typeahead的作者已经声明他们永远不会添加这个功能。实际上,他们建议在这种情况下也使用Select2。https://github.com/twitter/typeahead.js/issues/135 - andrewtweber

5

最佳答案似乎无法在最新的typeahead中使用,所以我提供以下内容。

演示

function MultiTypeahead(id, data, trigger, vertAdjustMenu)
{
    trigger = (undefined !== trigger) ? trigger : '';
    var validChars = /^[a-zA-Z]+$/;


    function extractor(query)
    {
        var result = (new RegExp('([^,; \r\n]+)$')).exec(query);
        if(result && result[1])
            return result[1].trim();
        return '';
    }

    var lastUpper = false;
    function strMatcher(id, strs) 
    {
        return function findMatches(q, sync, async) 
        {
            var pos = $(id).caret('pos');
            q = (0 < pos) ? extractor(q.substring(0, pos)) : '';

            if (q.length <= trigger.length)
                return;

            if (trigger.length)
            {
                if(trigger != q.substr(0, trigger.length))
                    return;

                q = q.substr(trigger.length);
            }

            if (!q.match(validChars))
                return;

            var firstChar = q.substr(0, 1);
            lastUpper = (firstChar === firstChar.toUpperCase() && firstChar !== firstChar.toLowerCase());

            var cpos = $(id).caret('position');
            $(id).parent().find('.tt-menu').css('left', cpos.left + 'px');
            if (vertAdjustMenu)
                $(id).parent().find('.tt-menu').css('top', (cpos.top + cpos.height) + 'px');

            var matches = [];
            var matches = [], substrRegex = new RegExp(q, 'i');
            $.each(strs, function(i, str) 
            {
                if (str.length > q.length && substrRegex.test(str))
                    matches.push(str);
            });

            if (!matches.length)
                return;

            sync(matches);
        };
    };

    var lastVal = '';
    var lastPos = 0;
    function beforeReplace(event, data)
    {
        lastVal = $(id).val();
        lastPos = $(id).caret('pos');
        return true;
    }

    function onReplace(event, data)
    {            
        if (!data || !data.length)
            return;

        if (!lastVal.length)
            return;

        var root = lastVal.substr(0, lastPos);
        var post = lastVal.substr(lastPos);

        var typed = extractor(root);
        if (!lastUpper && typed.length >= root.length && 0 >= post.length)
            return;

        var str = root.substr(0, root.length - typed.length);

        str += lastUpper ? (data.substr(0, 1).toUpperCase() + data.substr(1)) : data;
        var cursorPos = str.length;

        str += post;

        $(id).val(str);
        $(id).caret('pos', cursorPos);      
    }

    this.typeahead = 
        $(id).typeahead({hint: false, highlight: false}, {'limit': 5, 'source': strMatcher(id, data)})
                .on('typeahead:beforeselect', beforeReplace)
                .on('typeahead:beforeautocomplete', beforeReplace)
                .on('typeahead:beforecursorchange', beforeReplace)
                .on('typeahead:selected', function(event,data){setTimeout(function(){ onReplace(event, data); }, 0);})
                .on('typeahead:autocompleted', onReplace)
                .on('typeahead:cursorchange', onReplace)
                ;
}

编辑: 发现之前的代码有太多额外的东西,我将其缩小到了一个最小的工作示例。

这个 是之前发布的内容。


1
更新旧代码是个好习惯,尽管这很容易做到。我知道你为什么使用正则表达式,但它会使别人编辑你的代码变得困难。在我看来,唯一能改善你的答案的是换行而不是同一行,并且不使用“@”符号。 - SumNeuron

1
我虽然来晚了,但这是我为Bootstrap v4设计的东西。它还需要d3(因为我不太熟悉jQuery)。
您可以在http://sumneuron.gitlab.io/multitags/上运行示例enter image description here
它具有一些有用的功能,清晰易懂,应该能让任何发现此内容的人有一个良好的开端。特别是如果您曾经对标记的实现方式感到好奇。

enter image description here

代码可在https://gitlab.com/SumNeuron/multitags/pipelines获取。

逻辑大致如下:

if keydown in [enter, ","]:
    // logic of function "doneTyping" 
    text = parse(text) // get text from textarea and grab latest value
    if text is valid:
        renderTag(text) // put the text in a tag element
        updateHiddenForm(text) // update the hidden form to include the tag
    else:
        notifyUserOfInvalidTag(text) // alert user
else:
    // logic of function "stillTyping" 
    suggest = bloodhoundSearch(text) // use twitter typeahead
    updateSuggestionBox(suggest) // display results from typeahead

0

我想你可以编辑插件以允许多个选择(只需不关闭下拉菜单),并添加由逗号分隔的所选值。我唯一看到的问题是你不知道何时关闭下拉菜单。


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