Flatpickr представляет собой лёгкий и гибкий datepicker, который легко интегрируется в экосистему Angular благодаря отсутствию жёсткой привязки к DOM-структуре и минимальным требованиям к окружению. Основная задача интеграции — корректно синхронизировать жизненный цикл компонента Angular с инициализацией и уничтожением экземпляра Flatpickr.
Установка выполняется через npm:
npm install flatpickr
Дополнительно часто требуется типизация:
npm install --save-dev @types/flatpickr
Импорт базовых стилей:
import 'flatpickr/dist/flatpickr.min.css';
Простейший вариант интеграции строится через ViewChild и
прямую инициализацию после рендера шаблона.
import { Component, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import flatpickr, { Instance } from 'flatpickr';
@Component({
selector: 'app-datepicker',
template: `<input #input type="text" />`
})
export class DatepickerComponent implements AfterViewInit, OnDestroy {
@ViewChild('input', { static: false }) input!: ElementRef<HTMLInputElement>;
private fp!: Instance;
ngAfterViewInit(): void {
this.fp = flatpickr(this.input.nativeElement, {
dateFormat: 'Y-m-d',
enableTime: false
});
}
ngOnDestroy(): void {
this.fp?.destroy();
}
}
Ключевой момент заключается в том, что инициализация возможна только
после появления DOM-элемента, поэтому используется
AfterViewInit.
Интеграция с реактивными формами требует синхронизации состояния
Flatpickr с FormControl.
import { Component, AfterViewInit, OnDestroy, ElementRef, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import flatpickr, { Instance } from 'flatpickr';
@Component({
selector: 'app-datepicker',
template: `<input #input type="text" />`
})
export class DatepickerComponent implements AfterViewInit, OnDestroy {
@ViewChild('input') input!: ElementRef<HTMLInputElement>;
control = new FormControl<Date | string | null>(null);
private fp!: Instance;
ngAfterViewInit(): void {
this.fp = flatpickr(this.input.nativeElement, {
onChange: (selectedDates) => {
this.control.setValue(selectedDates[0] ?? null);
}
});
this.control.valueChanges.subscribe(value => {
if (value) {
this.fp.setDate(value as Date, false);
}
});
}
ngOnDestroy(): void {
this.fp?.destroy();
}
}
Синхронизация двусторонняя:
onChangesetDateБолее архитектурно корректный подход заключается в создании
директивы, которая превращает любой input в календарь.
import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core';
import flatpickr, { Instance, Options } from 'flatpickr';
@Directive({
selector: '[appFlatpickr]'
})
export class FlatpickrDirective implements OnInit, OnDestroy {
@Input('appFlatpickr') options: Options = {};
private fp!: Instance;
constructor(private el: ElementRef<HTMLInputElement>) {}
ngOnInit(): void {
this.fp = flatpickr(this.el.nativeElement, this.options);
}
ngOnDestroy(): void {
this.fp?.destroy();
}
}
Использование:
<input [appFlatpickr]="{ dateFormat: 'Y-m-d' }" />
Такой подход исключает дублирование логики и упрощает масштабирование.
Flatpickr не является полностью реактивным, поэтому изменение опций требует пересоздания экземпляра.
setOptions(newOptions: any): void {
this.fp?.destroy();
this.fp = flatpickr(this.input.nativeElement, newOptions);
}
При использовании в Angular важно учитывать, что пересоздание должно
быть синхронизировано с ChangeDetectionStrategy, чтобы
избежать лишних перерендеров.
Flatpickr поддерживает кастомные локали и форматирование через
date-fns-подобный синтаксис.
import { Russian } from 'flatpickr/dist/l10n/ru';
this.fp = flatpickr(this.input.nativeElement, {
locale: Russian,
dateFormat: 'd.m.Y'
});
Для Angular-приложений с интернационализацией часто используется динамическая подстановка локали:
@Input() locale: any;
ngOnChanges(): void {
if (this.fp && this.locale) {
this.fp.set('locale', this.locale);
}
}
Flatpickr позволяет объединять дату и время:
this.fp = flatpickr(this.input.nativeElement, {
enableTime: true,
dateFormat: 'Y-m-d H:i',
time_24hr: true
});
В Angular это часто связывается с
FormControl<string> вместо Date, чтобы
избежать проблем сериализации.
Angular повторно создает DOM-элементы при условных рендерах
(*ngIf), что приводит к необходимости защиты от утечек
памяти:
ngOnDestroyif (this.fp) {
this.fp.destroy();
}
Также важно учитывать, что повторная инициализация без уничтожения старого экземпляра приводит к наложению обработчиков событий.
В крупных Angular-приложениях Flatpickr часто загружается лениво:
async ngAfterViewInit() {
const flatpickrModule = await import('flatpickr');
this.fp = flatpickrModule.default(this.input.nativeElement, {});
}
Такой подход уменьшает начальный bundle и ускоряет first paint.
Flatpickr использует собственные CSS-классы, которые можно переопределять через глобальные стили Angular:
.flatpickr-calendar {
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}
При использовании ViewEncapsulation важно размещать
стили в styles.scss, иначе инкапсуляция может блокировать
переопределение.
В среде SSR доступ к window отсутствует, поэтому
инициализация должна быть защищена:
import { isPlatformBrowser } from '@angular/common';
import { Inject, PLATFORM_ID } from '@angular/core';
constructor(@Inject(PLATFORM_ID) private platformId: object) {}
ngAfterViewInit(): void {
if (isPlatformBrowser(this.platformId)) {
this.fp = flatpickr(this.input.nativeElement, {});
}
}
Flatpickr должен запускаться только в браузере, иначе SSR-процесс может упасть.
Flatpickr поддерживает плагины, которые можно подключать в Angular через конфигурацию:
import weekSelect from 'flatpickr/dist/plugins/weekSelect/weekSelect';
this.fp = flatpickr(this.input.nativeElement, {
plugins: [weekSelect()]
});
При архитектуре Angular-плагинов часто создаётся фабрика конфигураций:
export function createDatepickerOptions() {
return {
dateFormat: 'Y-m-d',
plugins: []
};
}
Flatpickr предоставляет набор событий:
this.fp = flatpickr(this.input.nativeElement, {
onOpen: () => console.log('open'),
onClose: () => console.log('close'),
onChange: (dates) => console.log(dates)
});
В Angular эти события обычно преобразуются в
@Output:
@Output() change = new EventEmitter<Date[]>();
onChange: (dates) => this.change.emit(dates)
Основные источники нагрузки:
FormControlOnPush стратегииОптимизация включает:
ChangeDetectionStrategy.OnPush@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
TypeScript-интеграция позволяет избежать ошибок при конфигурации:
import { Options } from 'flatpickr';
const options: Options = {
enableTime: true,
dateFormat: 'Y-m-d'
};
Использование строгих типов особенно важно при динамической генерации конфигураций в Angular сервисах.