Множественные обработчики

Архитектура событий в библиотеке строится вокруг системы хуков (hooks), позволяющей подключать несколько функций к одному и тому же событию без необходимости перезаписи предыдущих обработчиков. В основе лежит модель, где каждый жизненный этап календаря — открытие, закрытие, выбор даты, смена месяца или года — представляет собой точку расширения поведения.

Подход на основе массивов обработчиков

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

const fp = flatpickr("#input", {
  onChange: [
    function(selectedDates, dateStr, instance) {
      console.log("Первый обработчик:", dateStr);
    },
    function(selectedDates, dateStr, instance) {
      console.log("Второй обработчик:", selectedDates);
    }
  ]
});

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

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

После инициализации экземпляра возможно расширение поведения без пересоздания календаря. Обработчики могут добавляться в уже существующий массив.

fp.config.onOpen.push(function(selectedDates, dateStr, instance) {
  console.log("Дополнительный обработчик открытия");
});

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

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

Композиция через обёртки функций

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

const originalOnChange = fp.config.onChange;

fp.set("onChange", [
  function(...args) {
    console.log("До основного обработчика");
  },
  ...originalOnChange,
  function(...args) {
    console.log("После основного обработчика");
  }
]);

Такая структура позволяет явно управлять стадиями выполнения: предварительная обработка, основная логика и постобработка.

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

Каждый обработчик получает одинаковый набор аргументов:

  • selectedDates — массив выбранных дат
  • dateStr — строковое представление значения
  • instance — экземпляр календаря

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

onClose: [
  function(selectedDates, dateStr, instance) {
    instance.clear(); // один из обработчиков изменяет состояние
  },
  function(selectedDates, dateStr, instance) {
    console.log(instance.selectedDates);
  }
]

Конфликты и порядок выполнения

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

onChange: [
  function(dates, str, instance) {
    instance.config.enableTime = true;
  },
  function(dates, str, instance) {
    console.log(instance.config.enableTime);
  }
]

Во втором обработчике значение уже может быть изменено первым, что формирует цепочку зависимостей.

Использование событий DOM уровня

Помимо встроенных хуков, экземпляр календаря взаимодействует с DOM-элементом, на который он привязан. Это позволяет добавлять стандартные обработчики событий параллельно с внутренними механизмами.

const input = document.querySelector("#input");

input.addEventListener("change", () => {
  console.log("DOM change обработчик");
});

Такой подход существует параллельно с системой хуков и не заменяет её. В результате событие может быть обработано дважды: внутри календаря и на уровне DOM.

Инкапсуляция логики через именованные функции

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

function logDate(selectedDates, dateStr) {
  console.log("Дата:", dateStr);
}

function validateDate(selectedDates) {
  if (!selectedDates.length) {
    console.warn("Дата не выбрана");
  }
}

flatpickr("#input", {
  onChange: [logDate, validateDate]
});

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

Удаление и замена обработчиков

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

fp.set("onClose", fp.config.onClose.filter(fn => fn !== validateDate));

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

Изоляция побочных эффектов

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

let sharedState = 0;

onOpen: [
  function() {
    sharedState++;
  },
  function() {
    console.log(sharedState);
  }
]

Подобные конструкции формируют скрытые зависимости и усложняют прогнозирование поведения системы.

Приоритетность и расширение логики

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

onChange: [
  highPriorityHandler,
  mediumPriorityHandler,
  lowPriorityHandler
]

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

Переиспользование обработчиков в разных событиях

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

function syncState(selectedDates, dateStr, instance) {
  console.log("Синхронизация состояния");
}

flatpickr("#input", {
  onOpen: [syncState],
  onChange: [syncState],
  onClose: [syncState]
});

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