Select2 Custom Matcher, чтобы оставить параметры открытыми, если название группы совпадает

Я надеюсь, что мой вопрос имеет смысл - не был уверен, как лучше всего это описать. У меня есть сгруппированный ввод формы Select2 select примерно так:

  • Овощи
  • Латук
  • Помидоры
  • Лук
  • Фрукты
  • яблоки
  • Апельсины
  • Бананы
  • Спреды
  • Веджимайт
  • Нутелла
  • Арахисовое масло

Итак, вы начинаете вводить App и, конечно же, получаете Apples из раскрывающегося списка Select2. Если вы наберете veg, вы получите Vegemite и заголовок группы Vegetables, но все параметры будут скрыты. Я хотел бы, чтобы все параметры группы были видны, если поисковый запрос соответствует заголовку группы.

Я немного покопался в исходном коде 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

После некоторого поиска в Google я понял, что это заменяет акцентированные символы, которых, как я знаю, у меня нет, поэтому я удалил эту часть.

Теперь мой сопоставитель терпит неудачу с ошибками TypeError: data.indexOf is not a function. (In 'data.indexOf(term)', 'data.indexOf' is undefined) в моем браузере.

Я уверен, что я очень близок к этому, но я немного выше моего опыта и/или уровня навыков, чтобы закончить это. Любые указатели или идеи будут оценены.

ОБНОВЛЕНИЕ

Вот JSfiddle, с которым я работаю:

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


person Dan Tappin    schedule 13.03.2016    source источник
comment
Это действительно помогло бы, если бы вы создали jsFiddle вместо того, чтобы загружать его на GitHub. См.: jsfiddle.net.   -  person Clomp    schedule 17.03.2016
comment
Изменения, которые вы внесли, меня вполне устраивают. Кроме того, я не смог найти ни одного вхождения data.indexOf в Select2. Вы уверены, что ошибка Select2?   -  person Clavin    schedule 17.03.2016
comment
Это то, о чем ты говоришь? jsfiddle.net/xfw4tmbx/2   -  person Jared Farrish    schedule 17.03.2016


Ответы (1)


Из вашего вопроса я понял, что вы хотите иметь возможность показывать options для выбора, когда есть совпадение либо в тексте option, либо в атрибуте родительского значения optgroup option.

Это относительно просто: посмотрите на оба значения и, если одно из них совпадает, return true используйте параметр matcher в Select2:

(Примечание. Использование 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.* и выше изменили term и text на более сложный объект, поэтому он будет немного отличаться, но основная концепция та же. Как видите, все, что я делаю, — это использую jQuery для выбора родительского элемента option, если это элемент optgroup, и включаю его в проверку matcher.

Кроме того, optgroup будет отображаться, если показаны какие-либо из его дочерних элементов, поэтому вам нужно беспокоиться только об отображении одного или нескольких option, а не на самом деле «показывать» optgroup, показывая его вручную.

Если у вас есть другое требование, предоставьте демонстрационную скрипту (работающую/неработающую?), показывающую, что у вас есть, где мы можем ее запустить.

ИЗМЕНИТЬ

Пользовательское сопоставление Select2 значительно изменилось в версии 4.0. Вот пользовательский сопоставитель, опубликованный в этой проблеме GitHub. Он воспроизводится ниже для полноты картины.

Обратите внимание, что он вызывает себя для дочерних элементов (элементов option внутри элементов optgroup), поэтому modelMatcher() работает с элементами optgroup и option, но объединенный набор возвращается после удаления optgroup и option элементы, которые не совпадают. В приведенной выше версии вы получали каждый элемент 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/

person Jared Farrish    schedule 17.03.2016
comment
Это то, что я ищу, но я использую v4 и тему начальной загрузки, так что это близко. Я должен был указать, какую версию я использовал. Ваше решение работает, но я теряю поддержку темы. - person Dan Tappin; 17.03.2016
comment
@DanTappin. Создайте jsfiddle.net с вашим текущим кодом и дайте ссылку на него в комментарии здесь ([@my name ] поэтому я получаю уведомление). И когда вы говорите, что потеряли поддержку темы, что это значит? Вы заставили его работать с v4, но он не работает с Bootstrap, или вы перешли на v3.5.4? Что-то другое? - person Jared Farrish; 17.03.2016
comment
Я работаю над jsfiddle прямо сейчас. Как вы получаете ссылки CND на select2 is и css? Были ли они у вас? Я понизил свой драгоценный камень рельсов select2 до версии, которая была у вас, и ваш сопоставитель работает как шарм. Я опубликую ошибки, которые выдает v4. - person Dan Tappin; 17.03.2016
comment
jsfiddle добавлен в основной пост. Решил проблему с CDN. Как видите, вы получите TypeError: term.toUpperCase не является функцией. (В 'term.toUpperCase()' 'term.toUpperCase' не определено) ошибки. То же самое я видел в своем коде локально. - person Dan Tappin; 17.03.2016
comment
Ок... прогресс. Я наткнулся на этот github.com/select2/select2/issues/3034. Я не уверен, как я не нашел этого раньше. Я обновил свой jsfiddle: jsfiddle.net/jasper502/xfw4tmbx/14, он работает, но ваш код кажется более кратким и точным. Я буду играть с тем, что у вас есть, если вы меня не опередите. @джаредфарриш - person Dan Tappin; 17.03.2016
comment
@DanTappin - К сожалению, причина, по которой это кажется проще, заключается в том, что метод сопоставления был проще. Вы можете попробовать загрузить полную версию Select2, которая дает вам доступ к oldMatcher() (см. документацию по Select2), но у меня возникли проблемы с отображением подсовпадений. Здесь это работает (полурекурсивно, отсюда и непостижимость), но это действительно то, что вы ищете: jsfiddle.net/xfw4tmbx/16 И, кстати, его не так уж легко найти. В документации 4.0 должен быть пример кода, демонстрирующий, как работать с (действительно другой) новой методологией, а не только oldMatcher(). - person Jared Farrish; 18.03.2016
comment
Я согласен - документы не так ясны. Я собираюсь принять этот ответ, потому что вы нашли время, чтобы ответить, он действительно работает (для старой версии), и это побудило меня в конечном итоге найти рабочее решение. Спасибо. - person Dan Tappin; 18.03.2016
comment
child.parentText += data.parentText + " " + data.text; должно быть child.parentText = data.parentText + " " + data.text;, иначе child.parentText будет расти с каждым поиском... - person Fr0zenFyr; 25.07.2017