В сценариях с несколькими календарями на странице часто требуется
автоматическое копирование выбранной даты из одного поля в другое. В
библиотеке Pikaday это реализуется через программное управление
экземплярами календаря и использование методов setDate и
getDate.
Базовый принцип заключается в том, что каждый календарь управляется собственным экземпляром, а связь между ними строится через события выбора даты.
Основной механизм синхронизации в Pikaday — обработчик
onSelect. Он вызывается каждый раз, когда пользователь
выбирает дату.
const pickerA = new Pikaday({
field: document.getElementById('dateA'),
format: 'YYYY-MM-DD',
onSelect: function() {
const selectedDate = this.getDate();
pickerB.setDate(selectedDate, true);
}
});
const pickerB = new Pikaday({
field: document.getElementById('dateB'),
format: 'YYYY-MM-DD'
});
В этом примере выбранная дата из первого поля автоматически
копируется во второе. Второй аргумент true в
setDate предотвращает повторный вызов
onSelect, что критично для предотвращения циклических
обновлений.
При необходимости синхронизации в обе стороны требуется аккуратное управление флагами состояния, иначе возникает бесконечный цикл обновлений.
let isSyncing = false;
const pickerA = new Pikaday({
field: document.getElementById('dateA'),
onSelect: function() {
if (isSyncing) return;
isSyncing = true;
pickerB.setDate(this.getDate(), true);
isSyncing = false;
}
});
const pickerB = new Pikaday({
field: document.getElementById('dateB'),
onSelect: function() {
if (isSyncing) return;
isSyncing = true;
pickerA.setDate(this.getDate(), true);
isSyncing = false;
}
});
Подобный подход гарантирует, что обновление одного поля не вызывает цепную реакцию событий.
В Pikaday можно управлять значением календаря напрямую, без привязки к событиям интерфейса.
const dateValue = pickerA.getDate();
pickerB.setDate(dateValue);
Метод getDate возвращает объект Date,
который можно использовать для любых преобразований перед установкой в
другое поле.
Часто требуется не просто копировать дату, а преобразовывать её (например, добавлять смещение или округление).
const original = pickerA.getDate();
const shifted = new Date(original);
shifted.setDate(shifted.getDate() + 7);
pickerB.setDate(shifted);
Такой подход используется при реализации сценариев вроде «дата окончания через 7 дней от начала».
Одно из наиболее распространённых применений Pikaday — выбор диапазона дат, где второй календарь зависит от первого.
const startPicker = new Pikaday({
field: document.getElementById('start'),
onSelect: function() {
const startDate = this.getDate();
endPicker.setMinDate(startDate);
if (endPicker.getDate() && endPicker.getDate() < startDate) {
endPicker.setDate(startDate);
}
}
});
const endPicker = new Pikaday({
field: document.getElementById('end')
});
Здесь происходит не только копирование, но и ограничение допустимого
диапазона через setMinDate.
При работе с диапазонами важно учитывать обратную зависимость: изменение конечной даты может влиять на начальную.
const endPicker = new Pikaday({
field: document.getElementById('end'),
onSelect: function() {
const endDate = this.getDate();
startPicker.setMaxDate(endDate);
}
});
Таким образом обеспечивается логическая целостность диапазона.
При интенсивной синхронизации экземпляров Pikaday возникает риск множественных перерисовок и лишних вызовов событий. Для контроля используется единый управляющий слой.
const syncState = {
locked: false
};
function sync(from, to) {
if (syncState.locked) return;
syncState.locked = true;
to.setDate(from.getDate(), true);
syncState.locked = false;
}
Этот паттерн масштабируется на любое количество связанных календарей.
При переносе даты между полями важно учитывать формат отображения.
Pikaday позволяет использовать кастомные форматы через
toString и format.
const picker = new Pikaday({
field: document.getElementById('date'),
toString(date) {
return date.toLocaleDateString('ru-RU');
}
});
При копировании важно сохранять не только объект Date,
но и согласованность отображения, чтобы оба поля интерпретировали данные
одинаково.
В сложных формах может потребоваться синхронизация сразу нескольких календарей, например, при дублировании блока данных.
function copyDateToGroup(date, pickers) {
pickers.forEach(p => p.setDate(date, true));
}
const sharedDate = pickerA.getDate();
copyDateToGroup(sharedDate, [pickerB, pickerC, pickerD]);
Такой подход используется в интерфейсах бронирования, где один выбор распространяется на несколько сущностей.
При копировании важно учитывать возможность отсутствия даты. В
Pikaday getDate() может возвращать null.
const date = pickerA.getDate();
if (date) {
pickerB.setDate(date, true);
} else {
pickerB.setDate(null);
}
Это предотвращает некорректные состояния интерфейса и обеспечивает синхронное очищение полей.