Поведение экземпляра Tom Select при повторной инициализации напрямую
связано с тем, как библиотека управляет DOM-структурой, внутренним
состоянием и привязкой событий. Реинициализация возникает в ситуациях
динамического обновления интерфейса, когда исходный
<select> элемент заменяется, перерисовывается или
требует полного пересоздания логики выбора.
Каждый экземпляр Tom Select создаётся поверх стандартного
<select> элемента и формирует собственную обёртку с
дополнительной структурой DOM:
<select>При этом экземпляр хранится в памяти и привязывается к DOM-элементу
через ссылку, обычно доступную через element.tomselect.
Реинициализация требуется в следующих случаях:
<select> в SPA-логикеoptions с сервераТипичная проблема — повторная инициализация без очистки предыдущего экземпляра, приводящая к дублированию событий и конфликту DOM-узлов.
Перед созданием нового экземпляра требуется полное удаление текущего
состояния через метод destroy().
const select = document.querySelector('select');
if (select.tomselect) {
select.tomselect.destroy();
}
Метод destroy() выполняет:
<select>После этого DOM-элемент возвращается к состоянию, близкому к исходному, что позволяет безопасно выполнять повторную инициализацию.
После очистки экземпляра создаётся новый объект Tom Select:
new TomSelect('#select', {
create: true,
sortField: 'text'
});
Ключевым моментом является гарантия отсутствия активного экземпляра, иначе библиотека не выполняет полную пересборку структуры и начинает работать поверх существующих элементов.
Для предотвращения конфликтов используется проверка:
const el = document.querySelector('#select');
if (el.tomselect) {
el.tomselect.destroy();
}
new TomSelect(el, {
maxItems: 5
});
Такой подход исключает утечку обработчиков и двойную привязку логики.
При динамической генерации формы старый <select>
может быть заменён новым узлом. В этом случае важно учитывать, что
ссылка на экземпляр теряется.
const wrapper = document.querySelector('.wrapper');
wrapper.innerHTML = `
<select id="select">
<option value="1">A</option>
<option value="2">B</option>
</select>
`;
new TomSelect('#select');
В подобных сценариях повторная инициализация не требует
destroy(), так как предыдущий DOM уже удалён вместе с
экземпляром.
Некоторые параметры Tom Select не поддерживают динамическое изменение без пересоздания экземпляра. К таким относятся:
optionspluginsrenderloadПри необходимости изменения конфигурации используется полный цикл пересоздания:
function rebuildSelect(el, config) {
if (el.tomselect) {
el.tomselect.destroy();
}
return new TomSelect(el, config);
}
Перед вызовом destroy() часто требуется сохранить
текущее состояние:
const instance = select.tomselect;
const value = instance.getValue();
const options = instance.options;
После реинициализации значения можно восстановить:
const newInstance = new TomSelect(select, config);
newInstance.setValue(value);
Это особенно важно при асинхронной загрузке данных.
Возникает при повторной инициализации без destroy().
Симптомы:
onChangeПри многократной инициализации без очистки остаются скрытые контейнеры:
.ts-wrapper.ts-dropdownЭто приводит к росту DOM и падению производительности.
После частичной модификации <select> вручную Tom
Select может хранить устаревший state. В таких случаях требуется полное
пересоздание экземпляра вместо попытки обновления.
refreshOptions и частичная альтернатива
реинициализацииВ ряде случаев полная реинициализация избыточна. Tom Select предоставляет методы обновления:
select.tomselect.clearOptions();
select.tomselect.addOption({ value: 'x', text: 'New' });
select.tomselect.refreshOptions(false);
Однако такие методы не заменяют destroy(), если
изменяется фундаментальная структура.
В интерфейсах с модальными окнами и табами часто применяется повторная инициализация при каждом открытии:
function initModalSelect() {
const el = document.querySelector('#modal-select');
if (el.tomselect) {
el.tomselect.destroy();
}
new TomSelect(el, {
dropdownParent: 'body'
});
}
Особое внимание уделяется dropdownParent, так как
перенос dropdown в body предотвращает обрезание в
overflow-контейнерах.
В SPA-фреймворках (React, Vue, Svelte без обёрток или при интеграции через ref) реинициализация часто связана с жизненным циклом компонентов.
Типичный паттерн:
useEffect(() => {
const ts = new TomSelect(ref.current, config);
return () => {
ts.destroy();
};
}, [config]);
Если создать новый экземпляр поверх старого:
new TomSelect('#select');
new TomSelect('#select');
возникают:
Внутренний state библиотеки не рассчитан на параллельное существование нескольких экземпляров на одном элементе.
Tom Select сохраняет ссылку на себя в DOM-узле:
const ts = document.querySelector('#select').tomselect;
Это позволяет:
Практически устойчивая схема выглядит как комбинация проверок состояния и контролируемого пересоздания:
function safeInit(selector, config) {
const el = document.querySelector(selector);
if (!el) return;
if (el.tomselect) {
el.tomselect.destroy();
}
el.tomselect = new TomSelect(el, config);
return el.tomselect;
}
Такой подход предотвращает накопление экземпляров и гарантирует консистентность поведения даже при частых перерендерах интерфейса.