События изменения данных

Система событий в Tom Select играет ключевую роль при синхронизации интерфейса, данных формы и удалённых источников. События изменения данных позволяют отслеживать выбор элементов, удаление значений, создание новых записей и любые операции, влияющие на внутреннее состояние компонента.

Грамотное использование событий обеспечивает:

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

Базовая модель событий

Tom Select предоставляет собственную систему событий через метод on(). Все события регистрируются на экземпляре компонента.

Пример инициализации:

const select = new TomSelect('#users', {
    maxItems: 5
});

Подписка на событие:

select.on('change', function(value) {
    console.log(value);
});

Удаление обработчика:

select.off('change');

Регистрация одноразового обработчика:

select.once('change', function(value) {
    console.log('Событие сработало один раз');
});

Событие change

Назначение события

Событие change вызывается при любом изменении выбранных значений:

  • добавление элемента;
  • удаление элемента;
  • очистка списка;
  • программное изменение значения.

Это основное событие синхронизации состояния компонента.


Получение выбранных данных

select.on('change', function(value) {
    console.log(value);
});

Для одиночного выбора:

"admin"

Для множественного выбора:

["admin", "editor"]

Работа с DOM-событием change

Tom Select также инициирует стандартное DOM-событие:

document.querySelector('#users')
    .addEventListener('change', function(e) {
        console.log(e.target.value);
    });

Это особенно важно при интеграции с:

  • HTML-формами;
  • jQuery;
  • Vue;
  • React;
  • Angular;
  • системами валидации.

Автоматическая синхронизация формы

Tom Select обновляет оригинальный <select> или <input> автоматически.

<select id="skills" multiple>
    <option value="js">JavaScript</option>
    <option value="php">PHP</option>
</select>
new TomSelect('#skills');

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


Реакция на изменение значения

Динамическое отображение блоков

select.on('change', function(value) {

    if (value === 'company') {
        companyFields.style.display = 'block';
    } else {
        companyFields.style.display = 'none';
    }

});

Подгрузка зависимых данных

countrySelect.on('change', function(country) {

    loadCities(country);

});

Синхронизация нескольких компонентов

tagsSelect.on('change', function(values) {

    preview.innerHTML = values.join(', ');

});

Событие item_add

Назначение

Событие item_add вызывается при добавлении нового выбранного элемента.


Получение добавленного элемента

select.on('item_add', function(value, item) {

    console.log(value);
    console.log(item);

});

Параметры:

Параметр Описание
value Значение элемента
item DOM-узел выбранного элемента

Использование item_add

Логирование действий

select.on('item_add', function(value) {

    console.log(`Добавлен элемент: ${value}`);

});

Ограничение количества элементов

select.on('item_add', function() {

    if (this.items.length >= 5) {
        this.lock();
    }

});

Обновление счётчиков

select.on('item_add', function() {

    counter.textContent = this.items.length;

});

Отличие change от item_add

Событие Когда вызывается
change При любом изменении
item_add Только при добавлении

Событие item_remove

Назначение

Событие item_remove вызывается после удаления выбранного элемента.


Пример использования

select.on('item_remove', function(value) {

    console.log(`Удалён элемент: ${value}`);

});

Работа с интерфейсом

Скрытие связанных блоков

select.on('item_remove', function(value) {

    const section = document.querySelector(`[data-tag="${value}"]`);

    if (section) {
        section.remove();
    }

});

Разблокировка селекта

select.on('item_remove', function() {

    this.unlock();

});

Сравнение item_add и item_remove

Событие Действие
item_add Добавление
item_remove Удаление

Событие clear

Назначение

Событие clear вызывается после полной очистки выбранных значений.


Пример

select.on('clear', function() {

    console.log('Все элементы удалены');

});

Очистка зависимых компонентов

select.on('clear', function() {

    preview.innerHTML = '';
    counter.textContent = '0';

});

Автоматическое отключение кнопок

select.on('clear', function() {

    submitButton.disabled = true;

});

Событие option_add

Назначение

Событие option_add вызывается при добавлении новой опции в список доступных вариантов.

Важно отличать:

  • option_add — добавление варианта в список;
  • item_add — выбор пользователем.

Пример

select.on('option_add', function(value, data) {

    console.log(value);
    console.log(data);

});

Добавление новых данных с сервера

select.addOption({
    value: 10,
    text: 'Backend'
});

Сработает:

option_add

Использование для кэширования

select.on('option_add', function(value, data) {

    cache[value] = data;

});

Событие option_remove

Назначение

Событие вызывается при удалении опции из внутреннего списка.


Пример

select.on('option_remove', function(value) {

    console.log(`Опция удалена: ${value}`);

});

Очистка кэша

select.on('option_remove', function(value) {

    delete cache[value];

});

Событие option_clear

Назначение

Событие вызывается после полной очистки всех доступных опций.


Пример

select.on('option_clear', function() {

    console.log('Список опций очищен');

});

Повторная загрузка данных

select.on('option_clear', function() {

    loadDefaultOptions();

});

Событие optgroup_add

Назначение

Вызывается при добавлении группы опций.


Пример

select.on('optgroup_add', function(id, data) {

    console.log(id);
    console.log(data);

});

Событие optgroup_remove

Назначение

Срабатывает после удаления группы.


Пример

select.on('optgroup_remove', function(id) {

    console.log(`Группа удалена: ${id}`);

});

Событие optgroup_clear

Назначение

Полная очистка групп.


Пример

select.on('optgroup_clear', function() {

    console.log('Все группы удалены');

});

Событие initialize

Назначение

Вызывается после завершения инициализации компонента.


Использование initialize

select.on('initialize', function() {

    console.log('Tom Select готов');

});

Инициализация зависимых механизмов

select.on('initialize', function() {

    initValidation();
    initAnalytics();

});

Событие destroy

Назначение

Вызывается перед уничтожением экземпляра.


Пример

select.on('destroy', function() {

    console.log('Компонент уничтожается');

});

Очистка ресурсов

select.on('destroy', function() {

    clearInterval(timer);
    observer.disconnect();

});

Событие type

Назначение

Вызывается при вводе текста пользователем.


Пример

select.on('type', function(str) {

    console.log(str);

});

Реализация поиска

select.on('type', function(query) {

    analytics.track(query);

});

Проверка длины запроса

select.on('type', function(query) {

    if (query.length < 3) {
        return;
    }

    loadResults(query);

});

Событие load

Назначение

Срабатывает после завершения асинхронной загрузки данных.


Пример

select.on('load', function(data) {

    console.log(data);

});

Управление индикаторами загрузки

select.on('load', function() {

    loader.style.display = 'none';

});

Автоматическое обновление интерфейса

select.on('load', function(data) {

    resultCount.textContent = data.length;

});

Событие dropdown_open

Назначение

Вызывается при открытии выпадающего списка.


Пример

select.on('dropdown_open', function(dropdown) {

    console.log(dropdown);

});

Аналитика взаимодействия

select.on('dropdown_open', function() {

    analytics.track('dropdown_open');

});

Событие dropdown_close

Назначение

Срабатывает при закрытии выпадающего списка.


Пример

select.on('dropdown_close', function(dropdown) {

    console.log(dropdown);

});

Событие focus

Назначение

Вызывается при получении фокуса компонентом.


Пример

select.on('focus', function() {

    console.log('Фокус получен');

});

Событие blur

Назначение

Срабатывает при потере фокуса.


Пример

select.on('blur', function() {

    console.log('Фокус потерян');

});

Использование нескольких событий одновременно

Комплексная обработка

select.on('item_add', function(value) {

    console.log('Добавлено:', value);

});

select.on('item_remove', function(value) {

    console.log('Удалено:', value);

});

select.on('change', function(values) {

    save(values);

});

Централизованная система событий

Регистрация обработчиков

function registerEvents(select) {

    select.on('change', handleChange);
    select.on('item_add', handleAdd);
    select.on('item_remove', handleRemove);

}

Выделение логики в отдельные функции

function handleChange(values) {

    console.log(values);

}

function handleAdd(value) {

    console.log(value);

}

Использование контекста this

Внутри обработчиков this указывает на экземпляр Tom Select.

select.on('change', function() {

    console.log(this.items);

});

Получение выбранных элементов

select.on('change', function() {

    console.log(this.getValue());

});

Работа с внутренними данными

select.on('change', function() {

    console.log(this.options);

});

Временное отключение событий

Предотвращение рекурсивных изменений

let updating = false;

select.on('change', function(values) {

    if (updating) {
        return;
    }

    updating = true;

    sync(values);

    updating = false;

});

Снятие обработчиков

Удаление конкретного события

select.off('change');

Полная очистка событий

select.off();

Практическая архитектура событий

Разделение ответственности

Событие Назначение
change Синхронизация данных
item_add Реакция на добавление
item_remove Реакция на удаление
type Поиск
load Работа с AJAX
clear Очистка интерфейса

Типичные ошибки

Использование change вместо item_add

Ошибка:

select.on('change', function(value) {

    sendNotification(value);

});

При удалении события также будут отправляться уведомления.

Правильно:

select.on('item_add', function(value) {

    sendNotification(value);

});

Повторная регистрация обработчиков

Ошибка:

function init() {

    select.on('change', handler);

}

При повторной инициализации события будут дублироваться.


Игнорирование очистки событий

Ошибка особенно опасна в SPA-приложениях.

select.destroy();

Без очистки связанных ресурсов возможны:

  • утечки памяти;
  • зависшие обработчики;
  • дублирование запросов.

Интеграция с AJAX и событиями данных

Полный пример

const select = new TomSelect('#users', {

    valueField: 'id',
    labelField: 'name',
    searchField: 'name',

    load(query, callback) {

        fetch(`/api/users?q=${query}`)
            .then(res => res.json())
            .then(data => callback(data));

    }

});

select.on('type', function(query) {

    loader.style.display = 'block';

});

select.on('load', function() {

    loader.style.display = 'none';

});

select.on('item_add', function(value) {

    console.log(`Выбран пользователь ${value}`);

});

select.on('change', function(values) {

    saveForm(values);

});

События и реактивные интерфейсы

Интеграция с состоянием приложения

select.on('change', function(values) {

    store.commit('updateTags', values);

});

Обновление UI

select.on('item_add', function(value) {

    renderTag(value);

});

Отладка событий

Универсальный логгер

const events = [
    'change',
    'item_add',
    'item_remove',
    'clear',
    'type',
    'load'
];

events.forEach(event => {

    select.on(event, function(...args) {

        console.log(event, args);

    });

});

Производительность обработки событий

Минимизация тяжёлых операций

Плохо:

select.on('type', function(query) {

    expensiveOperation();

});

Лучше:

select.on('type', debounce(function(query) {

    expensiveOperation();

}, 300));

Исключение лишних обновлений

select.on('change', function(values) {

    if (JSON.stringify(values) === lastState) {
        return;
    }

    lastState = JSON.stringify(values);

    save(values);

});

Взаимодействие событий между собой

Многие действия вызывают цепочку событий.

Например:

select.addItem('admin');

Может вызвать:

  1. item_add
  2. change

Очистка:

select.clear();

Вызывает:

  1. clear
  2. change

Понимание последовательности событий критично при построении сложной логики интерфейса.