Цепочки событий

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

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

Каждое пользовательское действие в Awesomplete проходит через несколько стадий:

  1. Инициация ввода
  2. Фильтрация и построение списка
  3. Открытие списка
  4. Навигация по элементам
  5. Выбор элемента
  6. Финализация выбора
  7. Закрытие списка

Каждая стадия сопровождается событиями, которые можно перехватывать через addEventListener.


Событие ввода как старт цепочки

Цепочка начинается с изменения значения поля ввода. Awesomplete реагирует на стандартное событие input, после чего запускается пересчет списка.

input.addEventListener("input", function () {
    console.log("Ввод изменился");
});

На этом этапе формируется первичная выборка данных, но список ещё не отображается.


Фильтрация и подготовка данных

После ввода активируется внутренняя логика фильтрации. Хотя прямого публичного события для этого шага нет, он логически предшествует awesomplete-open.

Фильтрация может зависеть от:

  • minChars
  • filter (кастомная функция)
  • item (рендер элемента)
  • sort

Изменение этих параметров влияет на продолжение цепочки, особенно на момент открытия списка.


Открытие списка: awesomplete-open

Событие awesomplete-open фиксирует момент, когда список становится видимым.

input.addEventListener("awesomplete-open", function () {
    console.log("Список открыт");
});

Особенности:

  • вызывается один раз на открытие
  • может быть предотвращено через preventDefault() в некоторых реализациях расширений
  • часто используется для синхронизации UI (например, затемнение фона или позиционирование контейнеров)

Навигация и выделение элементов

После открытия начинается активная часть цепочки — перемещение по списку.

awesomplete-highlight

Срабатывает при смене активного элемента списка.

input.addEventListener("awesomplete-highlight", function (e) {
    console.log("Выделен элемент:", e.text);
});

Характеристики:

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

Выбор элемента: ключевая точка цепочки

awesomplete-select

Срабатывает до фактического применения значения.

input.addEventListener("awesomplete-select", function (e) {
    console.log("Выбор элемента:", e.text);
});

Особенность этого события — возможность вмешательства в процесс выбора. На этом этапе можно:

  • отменить выбор
  • заменить значение
  • выполнить асинхронную проверку

Пример блокировки выбора:

input.addEventListener("awesomplete-select", function (e) {
    if (e.text === "запрещено") {
        e.preventDefault();
    }
});

awesomplete-selectcomplete

Финальная стадия выбора, когда значение уже установлено в input.

input.addEventListener("awesomplete-selectcomplete", function (e) {
    console.log("Значение установлено:", input.value);
});

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

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

Закрытие списка

awesomplete-close

Завершает цепочку событий.

input.addEventListener("awesomplete-close", function () {
    console.log("Список закрыт");
});

Причины закрытия:

  • выбор элемента
  • потеря фокуса
  • пустой результат фильтрации
  • нажатие Escape

Полная цепочка событий в реальном сценарии

При стандартном вводе последовательность выглядит следующим образом:

  1. input
  2. внутренняя фильтрация
  3. awesomplete-open
  4. awesomplete-highlight (0-й элемент)
  5. пользователь навигацией меняет элемент → awesomplete-highlight
  6. пользователь подтверждает выбор → awesomplete-select
  7. установка значения → awesomplete-selectcomplete
  8. закрытие списка → awesomplete-close

Разветвление цепочек

Цепочки событий не всегда линейны. Возможны ветвления:

Ветка отмены выбора

Если в awesomplete-select вызывается preventDefault(), цепочка обрывается:

  • select → отмена → отсутствует selectcomplete
  • список может остаться открытым

Ветка пустого результата

Если фильтрация не возвращает совпадений:

  • input
  • фильтрация
  • отсутствие open
  • отсутствие highlight
  • возможное close

Вложенные цепочки и повторные циклы

Awesomplete допускает повторные циклы внутри одной сессии:

  • ввод → открытие → выбор → новый ввод
  • быстрые изменения input вызывают повторную инициацию цепочки до завершения предыдущей

Это требует осторожности при работе с состоянием:

let lock = false;

input.addEventListener("awesomplete-selectcomplete", function () {
    lock = true;
    setTimeout(() => lock = false, 200);
});

input.addEventListener("input", function () {
    if (lock) return;
});

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

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

  • логирование
  • изменение UI
  • запросы к API
  • валидация

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

input.addEventListener("awesomplete-select", handlerA);
input.addEventListener("awesomplete-select", handlerB);

Сначала выполнится handlerA, затем handlerB, что может изменить итоговую цепочку логики.


Конфликты внутри цепочек

Типичные конфликты возникают при:

  • изменении input.value в select и одновременном использовании selectcomplete
  • повторном вызове .evaluate() внутри событий
  • асинхронных операциях без блокировок

Пример проблемной схемы:

input.addEventListener("awesomplete-selectcomplete", function () {
    awesomplete.evaluate(); // может перезапустить цепочку
});

Управление сложными цепочками

Для контроля последовательностей используется явное разделение логики:

  • select — перехват решения
  • selectcomplete — побочные эффекты
  • open — UI-реакции
  • close — очистка состояния

Такое разделение предотвращает смешивание этапов и разрыв цепочки логики.


Асинхронные цепочки

Хотя Awesomplete работает синхронно, внешняя логика часто добавляет асинхронность:

input.addEventListener("awesomplete-select", async function (e) {
    const result = await fetch("/api/check?q=" + e.text);
    if (!result.ok) e.preventDefault();
});

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


Повторное использование цепочек

Одни и те же цепочки могут переиспользоваться в разных сценариях:

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

Разница заключается только в обработчиках, а сама структура событий остаётся одинаковой, что делает Awesomplete предсказуемым в построении UI-логики.