Система событий в Choices.js построена вокруг модели наблюдателя, где каждый экземпляр компонента выступает источником событий, отражающих изменения состояния селекта, пользовательские действия и внутренние этапы жизненного цикла. Такой подход обеспечивает слабую связанность логики и упрощает интеграцию с внешними частями приложения без необходимости модифицировать внутренний код библиотеки.
В основе лежит механизм регистрации обработчиков и их последующего вызова при наступлении определённых условий. Каждый экземпляр Choices инкапсулирует набор внутренних событий, связанных с:
События генерируются в строго определённые моменты выполнения внутренних методов. Это позволяет точно отслеживать изменения состояния без опроса (polling) или прямого доступа к внутренним структурам данных.
Каждое событие передаёт объект контекста, содержащий актуальное состояние экземпляра, а также дополнительные данные, специфичные для конкретного события.
Choices.js предоставляет метод
passedElement.addEventListener через DOM-обёртку, но
основной механизм подписки реализован через экземпляр объекта и его
внутренний event emitter.
Типовая модель подписки выглядит следующим образом:
const element = document.querySelector('#select');
const choices = new Choices(element);
choices.passedElement.element.addEventListener(
'addItem',
(event) => {
console.log('Добавлен элемент:', event.detail);
},
false
);
Внутри объекта event.detail содержится структура,
включающая:
value — значение выбранного элемента;label — отображаемый текст;id — внутренний идентификатор;customProperties — дополнительные данные, если они были
заданы;choice — ссылка на объект выбора.Такой формат позволяет унифицировать обработку данных вне зависимости от источника добавления элемента — пользовательский ввод, программное добавление или выбор из списка.
Событие init возникает после полной инициализации
экземпляра. В этот момент уже построена DOM-структура, загружены опции и
применены начальные настройки.
choices.passedElement.element.addEventListener('init', (event) => {
console.log('Компонент готов');
});
Инициализационное событие полезно для привязки дополнительной логики, зависящей от наличия готового интерфейса.
События showDropdown и hideDropdown
сигнализируют об изменении состояния выпадающего списка.
choices.passedElement.element.addEventListener('showDropdown', () => {
console.log('Список открыт');
});
choices.passedElement.element.addEventListener('hideDropdown', () => {
console.log('Список закрыт');
});
Эти события часто используются для управления стилями, аналитикой пользовательского поведения или синхронизацией с другими компонентами интерфейса.
Событие addItem является одним из ключевых. Оно
вызывается при добавлении нового значения в список выбранных
элементов.
choices.passedElement.element.addEventListener('addItem', (event) => {
const { value, label } = event.detail;
console.log(`Добавлено: ${label} (${value})`);
});
Важно учитывать, что событие срабатывает независимо от способа
добавления: пользовательский клик, ввод с клавиатуры или программный
вызов метода setChoiceByValue.
Событие removeItem вызывается при удалении значения из
выбранных элементов.
choices.passedElement.element.addEventListener('removeItem', (event) => {
console.log('Удалён элемент:', event.detail.value);
});
Удаление может происходить как через интерфейс (иконка удаления), так и программно через API. Это событие обеспечивает согласованную реакцию системы на любое изменение набора выбранных значений.
Событие change является агрегирующим и вызывается при
любом изменении состояния выбора. Оно не всегда предоставляет детальную
информацию о причине изменения, но отражает итоговое состояние.
choices.passedElement.element.addEventListener('change', (event) => {
console.log('Текущее значение:', event.target.value);
});
Это событие ближе к стандартному DOM change, но в
контексте Choices.js оно учитывает внутреннюю модель данных
библиотеки.
Встроенная система поиска генерирует событие search,
позволяющее отслеживать ввод пользователя в поле фильтрации.
choices.passedElement.element.addEventListener('search', (event) => {
console.log('Поисковый запрос:', event.detail.value);
});
Данное событие важно для реализации серверной фильтрации, когда результаты подгружаются динамически. В этом случае каждый ввод пользователя может инициировать запрос к API.
Особенность обработки заключается в том, что событие может вызываться многократно в процессе ввода, поэтому часто требуется реализация дебаунса на уровне обработчика.
Choices.js различает выбранные элементы и доступные опции. При динамическом изменении списка опций используются события:
addChoiceremoveChoiceПример:
choices.passedElement.element.addEventListener('addChoice', (event) => {
console.log('Добавлена опция:', event.detail.choice);
});
Эти события полезны при построении динамических списков, где данные обновляются из внешних источников.
Компонент генерирует события, связанные с фокусом и взаимодействием:
focusblurchoices.passedElement.element.addEventListener('focus', () => {
console.log('Компонент в фокусе');
});
Эти события соответствуют стандартному поведению DOM, но отражают состояние именно кастомного элемента Choices.js, а не нативного select.
Событие clear возникает при полном сбросе выбранных
значений.
choices.passedElement.element.addEventListener('clear', () => {
console.log('Выбор очищен');
});
Оно часто используется в формах с возможностью сброса фильтров или параметров поиска.
Каждое событие в Choices.js содержит унифицированный объект
event, который расширяет стандартный DOM Event. В
зависимости от типа события он может включать:
detail — специфические данные события;target — связанный DOM-элемент;timeStamp — время срабатывания;Пример структуры:
{
detail: {
value: "option_1",
label: "Option 1",
id: 3
},
target: HTMLSelectElement,
timeStamp: 1690000000000
}
Такое разделение позволяет отделять данные бизнес-логики от системных параметров события.
Внутренняя последовательность событий в Choices.js строго определена. Например, при добавлении нового элемента последовательность может выглядеть следующим образом:
addItem;change.Это важно при построении сложной логики, зависящей от точного момента обновления данных. Ошибки часто возникают при попытке модифицировать состояние внутри обработчиков без учёта порядка выполнения.
Choices.js не предназначает внешнюю генерацию своих внутренних событий напрямую, однако изменение состояния через API автоматически приводит к их вызову. Например:
choices.setValue([{ value: '1', label: 'Item 1' }]);
В результате будут сгенерированы соответствующие события добавления и изменения состояния. Это обеспечивает единообразие между пользовательскими и программными действиями.
При включённом режиме множественного выбора события
addItem и removeItem могут срабатывать
многократно в рамках одной операции. Это требует учёта батчинга
изменений, особенно при массовом обновлении данных.
В таких сценариях важно ориентироваться не на каждое отдельное
событие, а на итоговое состояние, получаемое через
change.
Каждый экземпляр Choices.js изолирован, однако внешняя логика может синхронизировать несколько компонентов через их события. Это позволяет строить связанные селекты, где изменение одного поля влияет на содержимое другого.
Пример архитектурного подхода:
change;setChoices;Такая схема позволяет строить каскадные зависимости без модификации внутренней логики библиотеки.