Select2 自定义匹配器以在组标题匹配时保持选项打开

Posted

技术标签:

【中文标题】Select2 自定义匹配器以在组标题匹配时保持选项打开【英文标题】:Select2 Custom Matcher to keep options open if group title matches 【发布时间】:2016-06-28 06:10:06 【问题描述】:

我希望我的问题是有道理的 - 不确定描述这个问题的最佳方式。我有一个分组的 Select2 选择表单输入,如下所示:

蔬菜 生菜 西红柿 洋葱 水果 苹果 橙子 香蕉 点差 素食主义者 能多益 花生酱

所以你开始输入App,当然你会从Select2下拉列表中得到Apples。如果您输入veg,您将获得VegemiteVegetables 组标题,但所有选项都被隐藏。如果搜索词与组标题匹配,我想保持所有组选项可见。

我在 select2 源代码中进行了一些挖掘,我认为这实际上很容易,但我可能是错的,如果我是对的,我会被困在如何使它工作上。这是源代码: https://github.com/select2/select2/blob/81a4a68b113e0d3e0fb1d0f8b1c33ae1b48ba04f/src/js/select2/defaults.js:

以及我创建的 Gist 与尝试将其粘贴到此处:

https://gist.github.com/jasper502/40b810e55b2195476342

我切换了代码的顺序并做了一些细微的变量名更改以反映这一点。我认为这将使选项组保持打开状态。我试图基于此制作一个自定义匹配器(请参阅我的 Gist),但我被困在它调用 DIACRITICS 的地方:

https://github.com/select2/select2/blob/8ad8f200ba8c9429d636453b8ee3bcf593e8c87a/src/js/select2/diacritics.js

经过一些谷歌搜索后,我意识到这是替换我知道我没有的重音字符,所以我删除了那部分。

现在我的匹配器因浏览器中的TypeError: data.indexOf is not a function. (In 'data.indexOf(term)', 'data.indexOf' is undefined) 错误而失败。

我确信我在这里非常接近,但我有点过头了,超出了我的经验和/或技能水平来完成这项工作。任何指针或想法将不胜感激。

更新

这是我正在使用的 JSfiddle:

https://jsfiddle.net/jasper502/xfw4tmbx/9/

【问题讨论】:

如果您为此创建了一个 jsFiddle,而不是将其上传到 GitHub,这将非常有帮助。见:jsfiddle.net 您所做的更改对我来说效果很好。此外,我在 Select2 中找不到任何 data.indexOf。你确定是 Select2 出错了吗? 你说的是这个吗? jsfiddle.net/xfw4tmbx/2 【参考方案1】:

我从您的问题中收集到的是,当option 文本或option 的父optgroup 值属性中存在匹配项时,您希望能够显示options 以​​供选择。

这相对简单:主要是查看两个值,如果匹配,return true 使用 Select2 的 matcher 选项:

(注意:使用 Select2 v3.5.4。)

(function() 
    function matcher(term, text, opt) 
        var $option = $(opt),
            $optgroup = $option.parent('optgroup'),
            label = $optgroup.attr('label');

        term = term.toUpperCase();
        text = text.toUpperCase();

        if (text.indexOf(term) > -1
             || (label !== undefined 
                 && label.toUpperCase().indexOf(term) > -1)) 
            return true;
        

        return false;
    

    $(".select2").select2(
        matcher: matcher
    );
)();

https://jsfiddle.net/xfw4tmbx/2/

v4.* 及更高版本将termtext 更改为更复杂的对象,因此会略有不同,但主要概念是相同的。正如你所看到的,我所做的只是使用 jQuery 来选择 option 的父元素,如果它是一个 optgroup 元素并且包括在 matcher 检查中。

此外,optgroup 将在其任何子项显示时显示,因此您只需担心显示一个或多个option,而无需手动“显示”optgroup显示它。

如果您有不同的要求,请提供一个(工作/不工作?)演示小提琴,展示您在哪里可以实际运行它。

编辑

Select2 自定义匹配在 4.0 版本中发生了显着变化。这是发布到此GitHub issue 的自定义匹配器。为了完整起见,它按原样复制如下。

请注意,它为子元素(optgroup 元素中的 option 元素)调用自身,因此 modelMatcher()optgroupoption 元素同时运行, 但在删除不匹配的 optgroupoption 元素后返回组合集。在上面的版本中,你得到了每个 option 元素,如果你想显示它(和父元素),只需返回 true/false。没有那么复杂得多,但你确实需要多考虑一下。

(function() 
    function modelMatcher(params, data) 
        data.parentText = data.parentText || "";

        // Always return the object if there is nothing to compare
        if ($.trim(params.term) === '') 
            return data;
        

        // Do a recursive check for options with children
        if (data.children && data.children.length > 0) 
            // Clone the data object if there are children
            // This is required as we modify the object to remove any non-matches
            var match = $.extend(true, , data);

            // Check each child of the option
            for (var c = data.children.length - 1; c >= 0; c--) 
                var child = data.children[c];
                child.parentText += data.parentText + " " + data.text;

                var matches = modelMatcher(params, child);

                // If there wasn't a match, remove the object in the array
                if (matches == null) 
                    match.children.splice(c, 1);
                
            

            // If any children matched, return the new object
            if (match.children.length > 0) 
                return match;
            

            // If there were no matching children, check just the plain object
            return modelMatcher(params, match);
        

        // If the typed-in term matches the text of this term, or the text from any
        // parent term, then it's a match.
        var original = (data.parentText + ' ' + data.text).toUpperCase();
        var term = params.term.toUpperCase();

        // Check if the text contains the term
        if (original.indexOf(term) > -1) 
            return data;
        

        // If it doesn't contain the term, don't return anything
        return null;
    


    $(".select2").select2(
        matcher: modelMatcher
    );
)();

https://jsfiddle.net/xfw4tmbx/16/

【讨论】:

这就是我正在寻找的,但我使用的是 v4 和引导主题,所以它很接近。我应该指定我使用的版本。我得到了你的解决方案,但我失去了主题支持。 @DanTappin - 请使用您当前的代码创建一个jsfiddle.net 并在此处的评论中链接到它([@my name] 以便我收到通知)。当你说你失去了主题支持时,这是什么意思?你让它与 v4 一起工作,但它不能与 Bootstrap 一起工作,或者你切换到 v3.5.4?还有什么? 我现在正在研究 jsfiddle。你如何获得到 select2 is 和 css 的 CND 链接?那些是你主持的吗?我将我的 select2 rails gem 降级到你拥有的版本,你的匹配器就像一个魅力。我将发布 v4 引发的错误。 我同意 - 文档一点也不清晰。我将接受这个答案,因为您花时间回复,它确实有效(对于旧版本),它促使我最终找到了一个有效的解决方案。谢谢。 child.parentText += data.parentText + " " + data.text; 应该是 child.parentText = data.parentText + " " + data.text; 否则,child.parentText 会随着每次搜索而不断增长...

以上是关于Select2 自定义匹配器以在组标题匹配时保持选项打开的主要内容,如果未能解决你的问题,请参考以下文章

如何创建自定义插值器以在 android 中应用翻译动画

创建自定义导航栏渲染器以在 xamarin 表单 IOS 项目中添加自定义后退按钮图标

更新接口构建器以匹配约束

如何编写自定义排序器以在 UI 中按名称对 springdoc swagger 标签进行排序?

Select2 - 选项项中的自定义输入字段,防止点击事件

Select2 选项不使用自定义滚动条滚动