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

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

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

Задача

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

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

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

Решение

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

Создайте чанк, например 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}[]">

Селект JS ищет строго по select[name="vendor"]. С vendor[] перестанут блокироваться пустые значения и не сработает «Назад». При открытии страницы по ссылке всё будет выглядеть исправно: выбранное значение отмечает сервер, а не JS.

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

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

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

Одно значение

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

Селект с 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 с []
«Назад» не возвращает прежнее значение селектаname с []
Фильтр нельзя снять, не сбросив формуВ чанке обёртки нет опции селекта «Все варианты»
Число товаров в опции селекта не меняется после фильтрацииЧисло выведено в текст без скрипта обновления — см. «Число товаров в опции селекта»
Крестик в блоке «Выбрано» не снимает фильтр-селектОграничение JS: при снятии фильтра селект не сбрасывается и отправляет прежнее значение. То же при «Назад» на страницу, где фильтр не был выбран. Снимайте опцией селекта «Все варианты» или кнопкой сброса формы
Счётчик выбранных значений в заголовке фильтра гаснет после фильтрацииОграничение JS: счётчик data-filter-badge считает только чекбоксы. У фильтра-селекта его не выводите