Показать выбранные параметры умного фильтра над товарами, с возможностью отмены выбора

Просмотров: 880

Задача: При выборе параметров товаров в умном фильтре показать выбранные параметры из чекбоксов в виде кнопок и предоставить возможность отмены выбора, кликая по этим кнопкам.

Показать выбранные параметры умного фильтра над товарами

Вносим изменения в шаблон умного фильтра

В начале section.php, в шаблоне каталога, добавляем пустой div с классом .smart_filter_checked_items. Например, разместим его над товарами этого раздела - в этот div будут добавляться кнопки с выбранными значениями.

Затем, в script.js шаблона умного фильтра (catalog.smart.filter), добавляем следующий код:

const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const checkedItemsContainer = document.querySelector('.smart_filter_checked_items');

function removeCheckboxAndClickSubmit(button) {
    const correspondingCheckbox = document.getElementById(button.id);
    if (correspondingCheckbox) {
        correspondingCheckbox.click();
    }
    button.remove();
}

checkedItemsContainer.addEventListener('click', (event) => {
    if (event.target.tagName === 'BUTTON') {
        removeCheckboxAndClickSubmit(event.target);
    }
});

function addCheckedButtonsOnLoad() {
    checkboxes.forEach((checkbox) => {
        if (checkbox.checked) {
            const buttonId = checkbox.id;
            const existingButton = checkedItemsContainer.querySelector(`#${buttonId}`);

            if (!existingButton) {
                const button = document.createElement('button');
                button.id = buttonId;
                button.textContent = checkbox.nextElementSibling.querySelector('span').textContent;
                checkedItemsContainer.appendChild(button);
            }
        }
    });
}

addCheckedButtonsOnLoad();

checkboxes.forEach((checkbox) => {
    checkbox.addEventListener('change', function () {
        const buttonId = this.id;
        const existingButton = checkedItemsContainer.querySelector(`#${buttonId}`);

        if (this.checked) {
            if (!existingButton) {
                const button = document.createElement('button');
                button.id = buttonId;
                button.textContent = this.nextElementSibling.querySelector('span').textContent;
                checkedItemsContainer.appendChild(button);
            }
        } else {
            if (existingButton) {
                existingButton.remove();
            }
        }
    });
});

Выбор всех чекбоксов и контейнера для отображения выбранных элементов:

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

Функция removeCheckboxAndClickSubmit: Эта функция используется для удаления кнопки выбранного параметра и автоматического снятия соответствующего чекбокса при нажатии на эту кнопку.

Обработчик событий для контейнера: Этот участок кода добавляет обработчик событий для контейнера, чтобы отслеживать клики по кнопкам, отображающим выбранные параметры. При нажатии на кнопку вызывается функция removeCheckboxAndClickSubmit.

Функция addCheckedButtonsOnLoad: Эта функция вызывается при загрузке страницы и проверяет все чекбоксы. Если чекбокс уже выбран, то создается кнопка с соответствующим значением и добавляется в контейнер.

Обработчик изменений чекбоксов: Здесь создается обработчик для каждого чекбокса. При изменении состояния чекбокса (если он становится выбранным или снимается выбор), скрипт либо создает новую кнопку и добавляет ее в контейнер, либо удаляет существующую кнопку из контейнера.

Пример работы скрипта на сайте используемом для выпуска видеокурса на 1С-Битрикс
Каталог bxstore.ru

Этот скрипт позволяет динамически отслеживать выбранные параметры умного фильтра и отображать их в виде кнопок для удобства пользователя. Кнопки также позволяют отменить выбор параметров, изменяя состояние соответствующих чекбоксов.

Алексей 28.11.2023
Михаил, добрый день. Очень полезная функция.
Но кнопки с выбранными параметрами появляются и сразу исчезают, если включен режим Ajax в каталоге.
Если Ajax выключить, то кнопки не исчезают, но и не отрабатывают на удаление.
Михаил Базаров 28.11.2023
Под Ajax режим да, надо докручивать этот способ, возможно позже допишу в заметку.

А вот почему не отрабатывают на удаление затрудняюсь сказать, проверил на одном проекте - все нормально. Попробуйте в консоли поизучать на конфликты, может с каким-то другим скриптом конфликтует у вас.
Гость 02.12.2023
Цитата
Алексей написал:
Михаил, добрый день. Очень полезная функция.
Но кнопки с выбранными параметрами появляются и сразу исчезают, если включен режим Ajax в каталоге.
Если Ajax выключить, то кнопки не исчезают, но и не отрабатывают на удаление.
Для того, чтобы работало без включенного ajax, можно немного изменить логику и работать с параметрами url, которые передает фильтр. Но для этого надо немного доработать шаблон самого умного фильтра. Там, где идет foreach с чекбоксами, в тег input надо добавить заполнение дата-атрибута data-url:
Код
data-url="<?= $ar['URL_ID']; ?>
После этого можно изменить функцию removeCheckboxAndClickSubmit из кода, который приводил Михаил
Код
    function removeCheckboxAndClickSubmit(button) {
        button.remove();
        const url = new URL(window.location).toString();
        const itemUrl = button.getAttribute('data-url');
        let newUrl;

        if (url.includes(`-${itemUrl}-or`)) {
            newUrl = url.replace(`-${itemUrl}-or`, '');
        } else {
            if (url.includes(`-or-${itemUrl}`)) {
                newUrl = url.replace(`-or-${itemUrl}`, '');
            } 
            else {
                newUrl = url.replace(`-${itemUrl}`, '');
            }
        }

        window.location.replace(newUrl);
    }

Этот код теперь становится нам не нужен, его можно просто удалить или закомментировать:
Код
    checkboxes.forEach((checkbox) => {        checkbox.addEventListener('change', function () {
            const buttonId = this.id;
            const existingButton = checkedItemsContainer.querySelector(`#${buttonId}`);

            if (this.checked) {
                if (!existingButton) {
                    const button = document.createElement('button');
                    button.id = buttonId;
                    button.textContent = this.nextElementSibling.querySelector('span').textContent;
                    checkedItemsContainer.appendChild(button);
                }
            } else {
                if (existingButton) {
                    existingButton.remove();
                }
            }
        });
    });
Алексей 05.12.2023
Проверил. Страница просто перезагружается и свойство не удаляется.

"url" и "itemUrl" приходят пустые. В итоге "newUrl" не изменяется при клике на кнопку.
Алексей 05.12.2023
Понял, что кнопкам тоже нужно передавать атрибут "data-url"

Поэтому код выглядит так и вроде работает:
Код
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const checkedItemsContainer = document.querySelector('.smart_filter_checked_items');

function removeCheckboxAndClickSubmit(button) {
        button.remove();
        const url = new URL(window.location).toString();
        const itemUrl = button.getAttribute('data-url'); // берем атрибут у кнопки, чтобу удалить из урл
        let newUrl;

        if (url.includes(`-${itemUrl}-or`)) {
            newUrl = url.replace(`-${itemUrl}-or`, '');
        } else {
            if (url.includes(`-is-${itemUrl}`)) { // тут изменение,т.к. у меня 'is' встречается чаще чем 'or'
                newUrl = url.replace(`-is-${itemUrl}`, '');
            } 
            else {
                newUrl = url.replace(`-${itemUrl}`, '');
            }
        }

        window.location.replace(newUrl);
   console.log(itemUrl);
}

checkedItemsContainer.addEventListener('click', (event) => {
    if (event.target.tagName === 'BUTTON') {
        removeCheckboxAndClickSubmit(event.target);
    }
});

function addCheckedButtonsOnLoad() {
    checkboxes.forEach((checkbox) => {
        if (checkbox.checked) {
            const buttonId = checkbox.id;
            const buttonData = checkbox.getAttribute('data-url'); // берем атрибуты у input checkbox
            const existingButton = checkedItemsContainer.querySelector(`#${buttonId}`);

            if (!existingButton) {
                const button = document.createElement('button');
                button.id = buttonId;
                button.textContent = checkbox.parentElement.querySelector('span').textContent; // тут изменение,т.к. у меня больше span в label
                button.setAttribute('data-url', buttonData); // добавляем атрибуты ко кнопкам
                checkedItemsContainer.appendChild(button);
            }
   console.log(buttonData);
        }
    });
}

addCheckedButtonsOnLoad();

Ну и вверху забыли ковычку в коде:

Там, где идет foreach с чекбоксами, в тег input надо добавить заполнение дата-атрибута data-url: data-url="<?= $ar['URL_ID']; ?>"
Вячеслав 06.12.2023
Алексей, точно, извиняюсь, упустил этот момент
Валерий 21.12.2023
Думаю умеет смысл уточнить, что для приведенного примера блок с классом .smart_filter_checked_items должен быть вставлен после вывода всех чекбоксов, например после вызова фильтра. Если он будет вызван ДО, то будет конфликт и чекбоксы будут работать некорректно.
Михаил Серегин 13.03.2024
Сделал легкий рефакторинг, может пригодится кому smart.mobile.filter