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

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

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

Базовая структура подключения событий:

new SlimSelect({
  select: '#example',
  events: {
    afterChange: (newVal) => {},
    beforeOpen: () => {},
    afterOpen: () => {},
    beforeClose: () => {},
    afterClose: () => {}
  }
});

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

afterChange: реакция на изменение значения

Событие afterChange вызывается после того, как значение <select> было изменено и внутреннее состояние компонента синхронизировано.

new SlimSelect({
  select: '#cities',
  events: {
    afterChange: (info) => {
      console.log(info);
    }
  }
});

Типичная структура info:

  • массив выбранных значений при multiple: true
  • одиночное значение при обычном режиме
  • метаданные выбранных опций (в зависимости от конфигурации)

Особенность механизма заключается в том, что событие срабатывает уже после обновления DOM и внутреннего state-слоя Slim Select, что делает его безопасным для побочных эффектов: AJAX-запросов, синхронизации с формами, обновления UI.

beforeChange: контроль изменения значения

Событие beforeChange выполняется до применения нового значения. Оно позволяет перехватывать изменение и при необходимости отменять его.

new SlimSelect({
  select: '#countries',
  events: {
    beforeChange: (newValue, oldValue) => {
      if (newValue === 'restricted') {
        return false;
      }
    }
  }
});

Возвращение false блокирует обновление состояния. Это ключевой механизм валидации и бизнес-логики на уровне компонента.

Характерные сценарии использования:

  • ограничение выбора по роли пользователя
  • динамическая блокировка значений
  • подтверждение действий перед изменением

beforeOpen: перехват открытия списка

Событие beforeOpen вызывается непосредственно перед отображением dropdown-списка. На этом этапе DOM уже готовится к рендеру, но визуальное открытие ещё не произошло.

new SlimSelect({
  select: '#products',
  events: {
    beforeOpen: () => {
      console.log('dropdown will open');
    }
  }
});

Данный хук используется для:

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

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

afterOpen: состояние открытого списка

Событие afterOpen срабатывает после того, как dropdown полностью отображён и доступен для взаимодействия.

new SlimSelect({
  select: '#users',
  events: {
    afterOpen: () => {
      console.log('opened');
    }
  }
});

На этом этапе можно безопасно:

  • инициировать фокусировку внутренних элементов
  • запускать анимации
  • логировать пользовательское поведение

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

beforeClose: контроль закрытия dropdown

Событие beforeClose вызывается перед закрытием списка. Оно аналогично beforeOpen, но работает в обратном направлении жизненного цикла.

new SlimSelect({
  select: '#tags',
  events: {
    beforeClose: () => {
      console.log('closing dropdown');
    }
  }
});

Типовые сценарии:

  • предотвращение закрытия при незавершённом вводе
  • проверка валидности выбранных данных
  • сохранение промежуточного состояния

Возврат false блокирует закрытие, что позволяет удерживать UI в открытом состоянии при необходимости.

afterClose: завершение жизненного цикла dropdown

Событие afterClose фиксирует момент полного завершения закрытия компонента. DOM-элементы списка уже удалены или скрыты, а внутренние состояния синхронизированы.

new SlimSelect({
  select: '#categories',
  events: {
    afterClose: () => {
      console.log('closed');
    }
  }
});

Используется для:

  • очистки временных данных
  • сброса UI-состояний
  • завершения аналитических операций

search: обработка ввода пользователя

Событие search активируется при вводе текста в поле поиска внутри dropdown. Оно является ключевым для реализации кастомной фильтрации и интеграции с серверным поиском.

new SlimSelect({
  select: '#searchable',
  events: {
    search: (searchTerm) => {
      console.log(searchTerm);
    }
  }
});

Часто используется для:

  • debounce-запросов к API
  • динамической подгрузки опций
  • локальной фильтрации больших наборов данных

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

Синхронизация событий и состояние компонента

Событийная модель Slim Select построена таким образом, что последовательность вызовов строго детерминирована:

  • beforeChange → изменение состояния → afterChange
  • beforeOpen → рендер → afterOpen
  • beforeClose → скрытие → afterClose

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

Особое значение имеет разделение на «до» и «после» события, которое формирует контрольную точку между намерением пользователя и фактическим изменением состояния.

Отмена действий через события

Механизм отмены реализован через возврат false в beforeChange, beforeOpen, beforeClose. Это позволяет внедрять бизнес-правила без необходимости вмешательства в ядро библиотеки.

Пример комбинированной логики:

new SlimSelect({
  select: '#roles',
  events: {
    beforeChange: (newVal) => {
      if (newVal === 'admin' && !window.isAllowed) {
        return false;
      }
    },
    beforeOpen: () => {
      if (window.locked) {
        return false;
      }
    }
  }
});

Такая модель делает Slim Select предсказуемым инструментом в больших приложениях, где контроль состояния должен быть централизован.

Работа с асинхронными сценариями

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

Например, при использовании search для серверной фильтрации:

new SlimSelect({
  select: '#async',
  events: {
    search: async (term) => {
      const res = await fetch(`/api?q=${term}`);
      const data = await res.json();
      // обновление опций выполняется отдельно
    }
  }
});

Важно учитывать, что Slim Select не ожидает завершения промисов и не синхронизирует их автоматически с UI.

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

При сложных сценариях взаимодействия событий возможны каскадные вызовы, особенно при программном изменении значения, которое может повторно инициировать afterChange. Это требует контроля за рекурсивными обновлениями состояния.

Типичный паттерн защиты:

let internalUpdate = false;

new SlimSelect({
  select: '#cascade',
  events: {
    afterChange: (val) => {
      if (internalUpdate) return;
      internalUpdate = true;

      // программное изменение
      // которое снова вызовет afterChange

      internalUpdate = false;
    }
  }
});

Такая техника предотвращает бесконечные циклы обновлений.

События как слой интеграции

Событийная система Slim Select выступает не только механизмом реагирования, но и интеграционным слоем между UI-компонентом и внешней бизнес-логикой. Через неё реализуются:

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

Архитектурно события образуют контракт между библиотекой и приложением, где Slim Select гарантирует порядок вызовов, а приложение определяет реакцию на них.