Skip to content
mFilter
mFilter
Фасетная фильтрация для MODX 3 с поддержкой SEO URL
  • MODX 3
  • PHP 8.1
  • Vue 3
  1. Компоненты
  2. mFilter
  3. Рецепты
  4. Фильтр выпадающим списком

Фильтр выпадающим списком ​

Выпадающий список <select> — дальше селект — вместо чекбоксов собирается из двух своих чанков. Готового в поставке нет, но JS обрабатывает селект сам.

Задача ​

Вывести значения одного фильтра селектом, а остальные оставить чекбоксами. Обычно это нужно, когда значений много — например, производителей несколько десятков — и выбирают одно.

С селектом JS уже умеет:

  • отправлять форму при выборе значения;
  • сбрасывать селект кнопкой сброса формы и крестиком в блоке «Выбрано»;
  • после фильтрации блокировать значения, по которым не осталось товаров;
  • по кнопке «Назад» переключать селект на значение, выбранное раньше;
  • учитывать выбор в счётчике data-filter-badge у заголовка фильтра.

Решение ​

Чанк значения ​

Создайте чанк, например catalog.filter.item:

fenom
{* Ключи фильтров, которые выводятся селектом. Тот же набор — в чанке обёртки *}
{set $selectKeys = ['vendor']}

{if $key in $selectKeys}
    <option value="{$value | esc}"{if $active} selected{/if}{if $disabled} disabled{/if}>{$label | esc}</option>
{else}
    <label class="mfilter-item">
        <input type="{if $multiple}checkbox{else}radio{/if}" name="{$key}{if $multiple}[]{/if}" value="{$value | esc}"{if $active} checked{/if}{if $disabled} disabled{/if}>
        {$label | esc} <span class="mfilter-count">{$count}</span>
    </label>
{/if}

Чанк обёртки ​

Создайте чанк, например catalog.filter:

fenom
{set $selectKeys = ['vendor']}

<div data-filter-key="{$key}">
    <div data-filter-label="{$label | esc}">{$label | esc}</div>

    {if $key in $selectKeys}
        <select name="{$key}">
            {* Первая опция селекта — «ничего не выбрано» *}
            <option value="">Все варианты</option>
            {* Остальные опции селекта выводит чанк значения *}
            {$items}
        </select>
    {else}
        {$items}
    {/if}
</div>

Вызов ​

fenom
{'!mFilterForm' | snippet : [
    'tpl' => 'catalog.filter',
    'tplItem' => 'catalog.filter.item',
]}

В примерах нет оформления — только то, без чего селект не заработает. Если у вас уже есть оформленный чанк обёртки, например копия стандартного mfilter.filter, добавьте в него ту же ветку {if $key in $selectKeys} вокруг {$items}. Атрибуты data-filter-key и data-filter-label у блока фильтра оставьте: по ним блок «Выбрано» находит название фильтра.

Все переменные обоих чанков — в разделе Чанки mFilterForm.

Почему два чанка ​

mFilterForm отрисовывает фильтр в два слоя: сначала каждое значение чанком значения, затем обёртку, куда значения попадают готовым HTML в $items. Поэтому опции селекта выводит чанк значения, а сам <select> — обёртка.

Чанк значения выбирается по типу фильтра, а не по ключу, и настройки «показывать селектом» в наборе фильтров нет:

Тип фильтраЧанк значения
number&tplSlider
colors&tplColor
boolean&tplBoolean
остальные&tplItem

Поэтому в $selectKeys можно добавлять только фильтры, значения которых идут через &tplItem.

Список ключей повторяется в обоих чанках: чанк значения отрисовывается раньше обёртки, и общих переменных у них нет.

Правила разметки ​

Без любого из этих правил селект отрисуется, но будет работать неправильно — и без ошибок в консоли.

name без [], если значение одно ​

fenom
{* Так *}
<select name="{$key}">

{* Не так *}
<select name="{$key}[]">

Блокировка пустых значений и счётчик у заголовка ищут селект строго по select[name="vendor"]. С vendor[] пустые значения перестанут блокироваться, а счётчик — считать выбор. Сразу после загрузки страницы разницы не видно: значения блокируются только после фильтрации.

Первая опция селекта — «Все варианты» ​

fenom
<select name="{$key}">
    <option value="">Все варианты</option>
    {$items}
</select>

Эта опция селекта стоит в чанке обёртки, перед {$items}: чанк значения выводит только значения фильтра. Пустое значение снимает фильтр, и JS эту опцию селекта никогда не блокирует. Без неё выбор в самом селекте не отменить — только кнопкой сброса формы или крестиком в блоке «Выбрано».

Несколько значений — multiple вместе с [] ​

fenom
{* Так *}
<select name="{$key}[]" multiple>
    {$items}
</select>

{* Не так *}
<select name="{$key}" multiple>

Селект с выбором нескольких значений отправляет все выбранные значения, снимает их по одному крестиком в блоке «Выбрано» и возвращает их по «Назад». Опция «Все варианты» ему не нужна: снять выбор — значит отменить выделение всех опций.

Без [] в имени «Назад» вернёт в селект только первое из выбранных значений, а следующее изменение формы молча снимет остальные.

С [] пустые значения не блокируются, и счётчик у заголовка выбор не считает. Если это важно, выводите такой фильтр чекбоксами: уберите его ключ из $selectKeys в обоих чанках.

Число товаров в опции селекта ​

У чекбоксов JS после фильтрации обновляет число товаров, а у опций селекта только блокирует пустые. Число, выведенное в текст опции селекта, устареет после первого же выбора в соседнем фильтре.

Проще всего число не выводить — как в чанке значения выше.

Если число нужно, сохраните название в data-label:

fenom
<option value="{$value | esc}" data-label="{$label | esc}"{if $active} selected{/if}{if $disabled} disabled{/if}>{$label | esc} ({$count})</option>

И обновляйте текст после каждой фильтрации — скрипт в любом месте страницы:

js
document.addEventListener('mfilter:success', (e) => {
    const suggestions = e.detail.response.suggestions || {};

    document.querySelectorAll('select option[data-label]').forEach((option) => {
        const filter = suggestions[option.parentElement.name];
        if (!filter) return;

        const item = (filter.values || []).find((v) => String(v.value) === option.value);
        option.textContent = `${option.dataset.label} (${item ? item.count : 0})`;
    });
});

Если не работает ​

СимптомПричина
Внутри блока чекбоксов появились отдельные <option>Ключ есть в $selectKeys чанка значения, но нет в обёртке
Селект пустой, а значения выведены чекбоксами рядомКлюч есть в обёртке, но нет в чанке значения
Селект обернул цветные образцы или переключательВ $selectKeys попал фильтр типа colors или boolean
Пустые значения не блокируются после фильтрацииname с []. У селекта с multiple это ограничение JS — см. «Несколько значений»
Счётчик у заголовка фильтра не считает выбор в селектеТо же: name с []
После «Назад» в селекте с multiple выбрано одно значение из несколькихmultiple без [] в имени
Выбор в селекте не отменить в самом селектеВ чанке обёртки нет опции селекта «Все варианты»
Число товаров в опции селекта не меняется после фильтрацииЧисло выведено в текст без скрипта обновления — см. «Число товаров в опции селекта»