Копирование дат между полями

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

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


Копирование даты через событие onSelect

Основной механизм синхронизации в 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;
    }
});

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


Использование getDate и setDate для ручного копирования

В 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 дней от начала».


Синхронизация диапазона дат (start / end)

Одно из наиболее распространённых применений 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);
}

Это предотвращает некорректные состояния интерфейса и обеспечивает синхронное очищение полей.