UNPKG

white-ui-kit

Version:

Модуль компонентов UI Имя модуля: `white-ui-kit`

210 lines (178 loc) 5.54 kB
import { Component, EventEmitter, forwardRef, HostListener, Input, OnDestroy, OnInit, ViewChild, Injector, HostBinding, AfterViewInit, } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, NgControl, } from '@angular/forms'; import { CdkOverlayOrigin, OverlayRef, } from '@angular/cdk/overlay'; import { Subscription } from 'rxjs'; import { format, parse, } from 'date-fns'; import * as ru from 'date-fns/locale/ru'; // Компоненты import { HitDatepickerPopupComponent, } from '../hit-datepicker-popup/hit-datepicker-popup.component'; // Сервисы import { HitOverlayService } from '../../services'; // Поле выбора даты @Component({ selector: 'hit-datepicker', templateUrl: './hit-datepicker.component.html', styleUrls: ['./hit-datepicker.component.scss'], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HitDatepickerComponent), multi: true, }], }) export class HitDatepickerComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor { constructor( private readonly injector: Injector, private readonly overlayService: HitOverlayService, ) { this.DATA.select.subscribe((date: Date) => { this.date = date; }); } // Флаг наличия ошибки public hasError: boolean; @HostBinding('attr.has-error') public get attrHasError(): string { return this.hasError ? 'has-error' : null; } // Ссылка на поле ввода @ViewChild('popupOrigin') private readonly popupOrigin: CdkOverlayOrigin; // Заглушка поля @Input() public placeholder: string; // Вызовем когда значение изменится private onChange: (value: Date) => void; // Вызовем при любом дествии пользователя с контроллом private onTouched: () => void; // Дата public _date: Date; public get date(): Date { return this._date; } public set date(value: Date) { this._date = value; this.DATA.selected = value; this.text = value && format(value, 'DD.MM.YYYY', { locale: ru }); if (this.onChange) { this.onChange(value); } } // Контрол private control: FormControl; // Подписка private subscription: Subscription; // Поле ввода public text: string; // Флаг, отключено public disabled: boolean = false; // Ссылка на календарь private overlayRef: OverlayRef; // Флаг, календарь открыт private get isCalendarOpened(): boolean { return !!(this.overlayRef && this.overlayRef.hasAttached()); } // Конфигурация всплывающего окна private readonly CONFIG = { elementRef: null, overlayComponent: HitDatepickerPopupComponent, }; // Данные календаря private readonly DATA = { selected: null, select: new EventEmitter<Date>(), }; // -------------------------------------------------------------------------- // Открыть/скрыть календаь public onToggle(): void { if (this.isCalendarOpened) { this.close(); } else { this.open(); } } // Обработчик заполнености маски public onCompleteMask(isCompleted: boolean): void { this.date = isCompleted ? parse( this.text .split('.') .reverse() .join('-'), ) : null; } // -------------------------------------------------------------------------- // Открыть окно private open(): void { if (!this.isCalendarOpened && !this.disabled) { this.overlayRef = this.overlayService.openContext(this.CONFIG, this.DATA); } } // Закрыть окно private close(): void { if (this.overlayRef) { this.overlayRef.dispose(); } } // -------------------------------------------------------------------------- // Реакция на клик хост-элемента @HostListener('click') public onClick(): void { if (this.onTouched) { this.onTouched(); } } // Вызовет форма, если значение изменилось извне public writeValue(date: Date): void { this.date = date; } // Сохраняем обратный вызов для изменений public registerOnChange(fn: any): void { this.onChange = fn; } // Сохраняем обратный вызов для "касаний" public registerOnTouched(fn: any): void { this.onTouched = fn; } // Установка состояния disabled public setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } // -------------------------------------------------------------------------- // Инициализация public ngOnInit(): void { this.CONFIG.elementRef = this.popupOrigin.elementRef; } // Инициализация завершена public ngAfterViewInit(): void { const ngControl: NgControl = this.injector.get(NgControl, null); if (ngControl) { this.control = ngControl.control as FormControl; this.subscription = this.control.statusChanges .subscribe(() => { this.hasError = !this.control.pristine && !this.control.valid; }); } } // Уничтожение public ngOnDestroy(): void { if (this.subscription) { this.subscription.unsubscribe(); } this.close(); } }