Синхронизация нескольких экземпляров Flatpickr часто требуется в интерфейсах, где несколько полей даты должны работать как единая логическая система. Наиболее распространённые сценарии включают диапазоны дат, связанные календарные фильтры, формы бронирования, панели аналитики и интерфейсы с параллельными временными окнами. В основе подхода лежит координация состояния между независимыми экземплярами календаря и управление их конфигурацией через программные методы и события.
Каждый экземпляр Flatpickr изолирован и управляет собственным DOM-элементом, однако предоставляет механизмы внешнего управления через API. Основные точки синхронизации:
onChange,
onOpen, onClose)setDate, clear,
set, jumpToDate)config)Ключевой принцип заключается в том, что один экземпляр выступает источником изменений, а остальные — реактивными получателями.
Наиболее прямолинейный способ синхронизации — использование
обработчика onChange, который распространяет изменения на
связанные экземпляры.
const fpStart = flatpickr("#start", {
onChange: function(selectedDates) {
fpEnd.set("minDate", selectedDates[0]);
}
});
const fpEnd = flatpickr("#end", {
onChange: function(selectedDates) {
fpStart.set("maxDate", selectedDates[0]);
}
});
В этой схеме каждый календарь ограничивает допустимый диапазон
другого. Важно учитывать, что изменение minDate и
maxDate не вызывает onChange, что
предотвращает циклические обновления.
При реализации диапазона дат требуется согласованное управление двумя значениями: началом и концом интервала. Более строгая модель предполагает централизованное состояние.
const state = {
start: null,
end: null
};
const fpStart = flatpickr("#start", {
onChange: (dates) => {
state.start = dates[0];
fpEnd.set("minDate", state.start);
if (state.end && state.end < state.start) {
state.end = null;
fpEnd.clear();
}
}
});
const fpEnd = flatpickr("#end", {
onChange: (dates) => {
state.end = dates[0];
fpStart.set("maxDate", state.end);
}
});
Такая структура устраняет рассинхронизацию логических границ диапазона и обеспечивает корректную валидацию порядка дат.
При двусторонней синхронизации возникает риск бесконечных циклов
обновления. Flatpickr не вызывает события при изменении ограничений,
однако программные вызовы setDate могут провоцировать
повторные триггеры.
Решение заключается в использовании флагов блокировки:
let syncing = false;
const fpA = flatpickr("#a", {
onChange: (dates) => {
if (syncing) return;
syncing = true;
fpB.setDate(dates[0], false);
syncing = false;
}
});
const fpB = flatpickr("#b", {
onChange: (dates) => {
if (syncing) return;
syncing = true;
fpA.setDate(dates[0], false);
syncing = false;
}
});
Второй аргумент setDate(..., false) отключает триггер
события onChange, снижая риск каскадных обновлений.
При увеличении количества экземпляров локальная логика становится неуправляемой. Централизованное состояние упрощает архитектуру.
const store = {
value: null,
subscribers: []
};
function setValue(date) {
store.value = date;
store.subscribers.forEach(fn => fn(date));
}
function subscribe(fn) {
store.subscribers.push(fn);
}
const fp1 = flatpickr("#input1", {
onChange: (d) => setValue(d[0])
});
const fp2 = flatpickr("#input2", {
onChange: (d) => setValue(d[0])
});
subscribe((date) => {
fp1.setDate(date, false);
fp2.setDate(date, false);
});
Такой подход превращает Flatpickr-инстансы в UI-слои поверх единого состояния, устраняя прямые зависимости между ними.
В системах фильтрации часто требуется, чтобы несколько календарей подчинялись одному набору правил: глобальному минимальному и максимальному диапазону.
const globalLimits = {
min: new Date(2024, 0, 1),
max: new Date(2026, 11, 31)
};
const instances = document.querySelectorAll(".date");
instances.forEach((el) => {
flatpickr(el, {
minDate: globalLimits.min,
maxDate: globalLimits.max
});
});
При изменении глобальных ограничений необходимо обновлять все
экземпляры через set:
instances.forEach((instance) => {
instance._flatpickr.set("minDate", new Date(2025, 0, 1));
});
Использование внутреннего свойства _flatpickr позволяет
получить доступ к API, но требует аккуратности, так как не является
частью DOM-абстракции.
В интерфейсах выбора периода часто применяется модель “главный календарь — зависимые календари”.
const master = flatpickr("#master", {
onChange: (dates) => {
const base = dates[0];
detail1.setDate(base, false);
detail2.setDate(new Date(base.getTime() + 86400000), false);
}
});
const detail1 = flatpickr("#d1");
const detail2 = flatpickr("#d2");
Здесь один источник определяет базовую дату, а остальные экземпляры вычисляют производные значения.
Иногда требуется синхронизировать не только значения, но и поведение календарей: формат отображения, режим выбора, доступные диапазоны.
function syncConfig(instances, config) {
instances.forEach((i) => {
i.set(config);
});
}
syncConfig([fp1, fp2], {
dateFormat: "Y-m-d",
enableTime: true,
time_24hr: true
});
Изменение конфигурации применяется мгновенно без пересоздания экземпляров, что критично для динамических интерфейсов.
При массовых обновлениях нескольких экземпляров важно избегать лишних перерасчётов DOM и повторных рендеров.
function batchUpdate(instances, date) {
requestAnimationFrame(() => {
instances.forEach((i) => i.setDate(date, false));
});
}
Использование requestAnimationFrame объединяет
обновления в один цикл отрисовки, снижая нагрузку.
В сложных формах часто присутствует цепочка зависимых дат:
Каждый элемент зависит от предыдущего.
start.onCha nge = (dates) => {
const d = dates[0];
milestone.set("minDate", d);
end.set("minDate", d);
};
milestone.onCha nge = (dates) => {
const d = dates[0];
end.set("minDate", d);
};
Такая каскадная модель требует строгого порядка обновлений, чтобы исключить конфликт ограничений.
Flatpickr можно рассматривать как источник событий, которые формируют поток данных.
function link(instances) {
instances.forEach((source) => {
source.config.onChange.push((dates) => {
instances.forEach((target) => {
if (target !== source) {
target.setDate(dates[0], false);
}
});
});
});
}
Подход превращает систему в событийную сеть, где каждый экземпляр реагирует на изменения других без жёсткой иерархии.
При включённом enableTime синхронизация усложняется
из-за необходимости учитывать часы и минуты. Прямое копирование даты
может приводить к неожиданным смещениям.
function syncDateTime(from, to) {
const d = new Date(from.selectedDates[0]);
to.setDate(d, false);
}
При необходимости нормализации времени используется явная установка
компонентов даты через setHours, setMinutes,
setSeconds.
Система синхронизации нескольких экземпляров Flatpickr строится на сочетании событийной модели, централизованного состояния и управляемых программных обновлений. Баланс между реактивностью и контролем обновлений определяет стабильность поведения интерфейса при росте количества связанных календарей.