НейроАгент

Как уничтожить Fancybox в Bitrix после AJAX загрузки

Решение проблемы TypeError при уничтожении экземпляра Fancybox после AJAX в Bitrix. Узнайте правильные методы destroy() для разных версий Fancybox и интеграции с Bitrix AJAX.

Вопрос

Как правильно уничтожить (destroy) экземпляр Fancybox после AJAX-загрузки в Bitrix?

Я пытаюсь перезапустить Fancybox после AJAX-загрузки в компоненте catalog.element Bitrix. Код для слайдера glide.js работает корректно:

javascript
let fancyboxInstance = null;

document.addEventListener('DOMContentLoaded', function() {
    createOrUpdateFancybox();
});

BX.addCustomEvent("onAjaxSuccess", function() {
    createOrUpdateFancybox();
});

function createOrUpdateFancybox() {
    const slElements = document.querySelectorAll('[data-fancybox]');
    const slExist = slElements.length > 0;

    if (!slExist) return; 

    if (fancyboxInstance) {
        fancyboxInstance.destroy(); 
    }

    fancyboxInstance = Fancybox.bind("[data-fancybox]");
}

Однако Bitrix выводит в консоли ‘processing’ и ошибку: TypeError: fancyboxInstance.destroy is not a function. Метод close() также не работает. Как правильно уничтожить предыдущий экземпляр Fancybox перед созданием нового после AJAX-загрузки?

НейроАгент

Для правильного уничтожения экземпляра Fancybox после AJAX-загрузки в Bitrix необходимо использовать статический метод destroy() вместо вызова его на экземпляре. Ваша проблема заключается в том, что метод destroy() является статическим методом объекта Fancybox, а не методом экземпляра.

Содержание

Основная проблема и решение

Ошибка TypeError: fancyboxInstance.destroy is not a function возникает потому, что в вашем коде вы пытаетесь вызвать метод destroy() на экземпляре Fancybox, в то время как этот метод является статическим. Согласно документации Fancybox, правильный вызов:

javascript
// Закрываем все экземпляры и отвязываем все события
$.fancybox.destroy();

или для современных версий:

javascript
Fancybox.destroy();

Правильный код для Bitrix

Вот исправленная версия вашего кода:

javascript
let fancyboxInstance = null;

document.addEventListener('DOMContentLoaded', function() {
    createOrUpdateFancybox();
});

BX.addCustomEvent("onAjaxSuccess", function() {
    createOrUpdateFancybox();
});

function createOrUpdateFancybox() {
    const slElements = document.querySelectorAll('[data-fancybox]');
    const slExist = slElements.length > 0;

    if (!slExist) return; 

    // Уничтожаем все существующие экземпляры Fancybox
    if (typeof Fancybox !== 'undefined') {
        Fancybox.destroy();
    }
    
    // Или для старых версий:
    // if (typeof $.fancybox !== 'undefined') {
    //     $.fancybox.destroy();
    // }

    // Создаем новый экземпляр
    fancyboxInstance = Fancybox.bind("[data-fancybox]");
}

Различия между версиями Fancybox

Важно учитывать, что разные версии Fancybox имеют разные API:

  • Fancybox 2: Не включает методы destroy или update согласно StackOverflow
  • Fancybox 3+: Включает статический метод destroy() как показано в документации
  • Fancybox 4: Современная версия с полным API
javascript
// Для Fancybox 3/4
Fancybox.destroy();

// Для старых версий (альтернатива)
$(document).unbind('click.fb-start');
$('[data-fancybox]').unbind('click.fb');

Полная реализация с обработкой ошибок

javascript
let fancyboxInstance = null;

document.addEventListener('DOMContentLoaded', function() {
    initFancybox();
});

BX.addCustomEvent("onAjaxSuccess", function() {
    initFancybox();
});

function initFancybox() {
    try {
        const fancyboxElements = document.querySelectorAll('[data-fancybox]');
        
        if (fancyboxElements.length === 0) {
            return;
        }

        // Уничтожаем предыдущие экземпляры
        destroyFancybox();
        
        // Инициализируем новый экземпляр
        fancyboxInstance = Fancybox.bind("[data-fancybox]", {
            // ваши опции
        });
        
    } catch (error) {
        console.error('Ошибка инициализации Fancybox:', error);
    }
}

function destroyFancybox() {
    try {
        // Проверяем доступность Fancybox
        if (typeof Fancybox !== 'undefined') {
            Fancybox.destroy();
        } else if (typeof $.fancybox !== 'undefined') {
            // Для старых версий
            $.fancybox.close();
            $(document).unbind('click.fb-start');
            $('[data-fancybox]').unbind('click.fb');
        }
        
        // Сбрасываем переменную экземпляра
        fancyboxInstance = null;
        
    } catch (error) {
        console.error('Ошибка уничтожения Fancybox:', error);
    }
}

Альтернативные методы уничтожения

Если метод destroy() недоступен в вашей версии Fancybox, можно использовать альтернативные подходы:

1. Отвязка событий

javascript
function destroyFancyboxLegacy() {
    // Отвязываем все Fancybox события
    $(document).unbind('click.fb-start');
    $(document).unbind('click.fb');
    $(document).unbind('click.fb-close');
    
    // Отвязываем события с элементов
    $('[data-fancybox]').unbind('click.fb');
    
    // Закрываем все открытые экземпляры
    if (typeof $.fancybox !== 'undefined') {
        $.fancybox.close();
    }
}

2. Установка опции live: false

При инициализации Fancybox добавьте опцию live: false:

javascript
fancyboxInstance = Fancybox.bind("[data-fancybox]", {
    live: false  // Это предотвращает автоматическую привязку к новым элементам
});

Как указано в StackOverflow, “Unbinding the .fancybox links only works if the live parameter is set to false.”

Интеграция с Bitrix AJAX

При работе с Bitrix AJAX важно учитывать особенности обработки событий:

javascript
document.addEventListener('DOMContentLoaded', function() {
    initFancybox();
});

// Обработка успешного AJAX-запроса
BX.addCustomEvent("onAjaxSuccess", function() {
    // Небольшая задержка для гарантии, что DOM обновлен
    setTimeout(initFancybox, 100);
});

// Обработка ошибок AJAX
BX.addCustomEvent("onAjaxFailure", function() {
    destroyFancybox();
});

function initFancybox() {
    const fancyboxElements = document.querySelectorAll('[data-fancybox]');
    
    if (fancyboxElements.length === 0) {
        return;
    }

    // Проверяем, что контент действительно загружен
    let hasValidContent = false;
    fancyboxElements.forEach(element => {
        if (element.getAttribute('href') && element.getAttribute('href').trim() !== '') {
            hasValidContent = true;
        }
    });

    if (!hasValidContent) {
        return;
    }

    destroyFancybox();
    
    try {
        fancyboxInstance = Fancybox.bind("[data-fancybox]", {
            // Опции для Bitrix
            touch: false,
            // другие опции
        });
    } catch (error) {
        console.error('Ошибка при инициализации Fancybox в Bitrix:', error);
    }
}

Заключение

  1. Используйте статический метод Fancybox.destroy() или $.fancybox.destroy() вместо вызова на экземпляре
  2. Проверяйте версию Fancybox и используйте соответствующий API
  3. Обрабатывайте ошибки при инициализации и уничтожении
  4. Используйте задержку при обработке событий Bitrix AJAX для гарантии обновления DOM
  5. Рассмотрите альтернативные методы для старых версий Fancybox отвязки событий

Правильная реализация позволит избежать конфликтов при перезагрузке контента через AJAX в Bitrix и обеспечит корректную работу всплывающих окон.

Источники

  1. Fancybox Documentation - Core methods
  2. StackOverflow - How to destroy Fancybox?
  3. StackOverflow - Does the Fancybox instance need a reinitialise method?
  4. GitHub Issue - Reset a fancybox instance
  5. 1C-Bitrix Community - Fancybox и ajax битрикса
  6. Fancybox API Methods