最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Select2 Custom Matcher to keep options open if group title matches - Stack Overflow

programmeradmin20浏览0评论

I hope my question makes sense - wasn't sure on the best way to describe this. I have a grouped Select2 select form input something like this:

  • Vegetables
  • Lettuce
  • Tomatoes
  • Onions
  • Fruit
  • Apples
  • Oranges
  • Bananas
  • Spreads
  • Vegemite
  • Nutella
  • Peanut Butter

So you start typing App and of course you get Apples from the Select2 dropdown. If you type veg you get Vegemite and the Vegetables group heading but all the options are hidden. I would like to keep all the group options visible if a search term matches the group heading.

I did some digging in the select2 source code and I think it's actually easy but I could be wrong and if I am right I am stuck on how to make it work. Here is the source code: .js:

and a Gist I created vs. trying to paste it in here:

I switched the order of the code and made some slight variable name changes to reflect this. I think this would keep the option group open. I tried to make a custom matcher based on this (see my Gist) but I was stuck at the point where it calls DIACRITICS:

.js

After some Googling I realized that this is replacing accented characters which I know I don't have so I removed that portion.

Now my matcher fails with TypeError: data.indexOf is not a function. (In 'data.indexOf(term)', 'data.indexOf' is undefined) errors in my browser.

I am sure I am very close here but I am a bit over my head and beyond my experience and/or skill level to finish this off. Any pointers or ideas would be appreciated.

UPDATE

Here is a JSfiddle with what I am working with:

/

I hope my question makes sense - wasn't sure on the best way to describe this. I have a grouped Select2 select form input something like this:

  • Vegetables
  • Lettuce
  • Tomatoes
  • Onions
  • Fruit
  • Apples
  • Oranges
  • Bananas
  • Spreads
  • Vegemite
  • Nutella
  • Peanut Butter

So you start typing App and of course you get Apples from the Select2 dropdown. If you type veg you get Vegemite and the Vegetables group heading but all the options are hidden. I would like to keep all the group options visible if a search term matches the group heading.

I did some digging in the select2 source code and I think it's actually easy but I could be wrong and if I am right I am stuck on how to make it work. Here is the source code: https://github./select2/select2/blob/81a4a68b113e0d3e0fb1d0f8b1c33ae1b48ba04f/src/js/select2/defaults.js:

and a Gist I created vs. trying to paste it in here:

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

I switched the order of the code and made some slight variable name changes to reflect this. I think this would keep the option group open. I tried to make a custom matcher based on this (see my Gist) but I was stuck at the point where it calls DIACRITICS:

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

After some Googling I realized that this is replacing accented characters which I know I don't have so I removed that portion.

Now my matcher fails with TypeError: data.indexOf is not a function. (In 'data.indexOf(term)', 'data.indexOf' is undefined) errors in my browser.

I am sure I am very close here but I am a bit over my head and beyond my experience and/or skill level to finish this off. Any pointers or ideas would be appreciated.

UPDATE

Here is a JSfiddle with what I am working with:

https://jsfiddle/jasper502/xfw4tmbx/9/

Share Improve this question edited Mar 17, 2016 at 17:56 Dan Tappin asked Mar 13, 2016 at 4:50 Dan TappinDan Tappin 3,0325 gold badges43 silver badges89 bronze badges 3
  • This would really help if you created a jsFiddle of this, instead of uploading it to GitHub. See: jsfiddle – Clomp Commented Mar 16, 2016 at 22:39
  • The changes you made work just fine for me. Furthermore, I couldn't find any occurrence of data.indexOf in Select2. Are you sure it's Select2 that's erroring? – Clavin Commented Mar 16, 2016 at 23:07
  • Is this what you're talking about? jsfiddle/xfw4tmbx/2 – Jared Farrish Commented Mar 16, 2016 at 23:14
Add a ment  | 

1 Answer 1

Reset to default 17 +100

What I gather from your question is you want to be able to show options for selection when there's a match in either the option text OR the option's parent optgroup value attribute.

This is relatively straightforward: Mainly, look at both of the values and if either matches, return true using Select2's matcher option:

(Note: Using 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/xfw4tmbx/2/

v4.* and above changed the term and text to a more plex object, so it'll be slightly different, but the main concept is the same. As you can see, all I'm doing is using jQuery to select up to the option's parent if it's an optgroup element and including that in the matcher check.

Also, an optgroup will display if any of it's children are shown, so you only have to worry about displaying one or more of the option's, and not actually "show" the optgroup by manually showing it.

If you have a different requirement, please provide a (working/non-working?) demonstration fiddle showing what you have where we can actually run it.

EDIT

Select2 custom matching changed significantly with the 4.0 release. Here is a custom matcher that was posted to this GitHub issue. It is reproduced as-is below for pleteness.

Notice that it's calling itself for child elements (the option elements within the optgroup elements), so modelMatcher() is running against both the optgroup and the option elements, but the bined set is returned after removing the optgroup and option elements that don't match. In the version above, you got every option element and simply returned true/false if you wanted it (and the parent) displayed. Not that much more plicated, but you do have to think about it a little bit more.

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

        // Always return the object if there is nothing to pare
        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/xfw4tmbx/16/

发布评论

评论列表(0)

  1. 暂无评论